[
  {
    "path": ".editorconfig",
    "content": "# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# --------------------------------------------------------------\n# Config Type   : EditorConfig\n# Config Authors: 曾奥然 <ccmywish@qq.com>\n# Contributors  : Nil Null <nil@null.org>\n# Created On    : <2023-09-06>\n# Last Modified : <2025-08-27>\n#\n# 请参考 ./doc/03-为什么拒绝使用代码格式化工具.md\n#\n# http://editorconfig.org\n# --------------------------------------------------------------\n\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\n\n# VS Code 对该配置(为 false)的实现有问题，这是确定的，\n# 然而 CLion 似乎对该配置(为 false)的实现是正确的，这导致不同贡献者反而产生了冲突\n# 所以我们现在改成 true\ninsert_final_newline = true\n\n[*.{c,C,cpp,cxx,cc,h,hpp}]\nindent_style = space\nindent_size = 2\n\n[*.pl]\nindent_size = 4\n\n[*.{raku,rakumod,rakutest}]\nindent_size = 2\n\n[*.ps1]\nindent_size = 4\n\n[*.{sh,bash}]\nindent_size = 2\n\n[Makefile,makefile,*.{mk,make,makefile}]\nindent_style = tab\n\n# 使用 VS Code 生成文件的默认格式\n[*.json]\nindent_size = 4\n\n[*.{yaml,yml}]\nindent_size = 2\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "custom: [\n  'https://afdian.com/a/ccmywish',\n  'https://github.com/ccmywish/support-my-oss-work'\n]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/01-Report_Bug.yml",
    "content": "name: 🐞 Bug 报告\ndescription: 有 Bug 了吗?\ntitle: \"详细报告BUG是chsrc用户的一大美德\"\n# labels: [ ]\ntype: Bug\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        感谢花时间填写此 Bug 报告!\n\n        1. 你可能是通过包管理器安装的 `chsrc`，其版本往往稍旧，你可先尝试使用REAME中提供的安装命令来获取最新版本\n\n        2. 有时 Bug 是在最新版本中引入的，此时你可在安装命令时指定 `-v` 参数临时使用旧版本解决燃眉之急，详情查看README\n\n  - type: textarea\n    id: what-did-you-do\n    attributes:\n      label: 你操作了什么？\n      # description: 告诉我们，在问题出现之前你使用 chsrc 做了什么?\n      placeholder: 我运行了 chsrc set <target>...\n    validations:\n      required: true\n\n  - type: textarea\n    id: what-happened\n    attributes:\n      label: 发生了什么？\n      # description: 告诉我们，发生了什么你认为不该出现的事？屏幕截图或视频记录都很有帮助\n      placeholder: 换源没有成功...\n    validations:\n      required: true\n\n  - type: textarea\n    id: what-should-happen\n    attributes:\n      label: 本应该怎么样？\n      # description: 告诉我们，正常的或你期望看到的 运行结果和状态\n      placeholder: 我希望 chsrc 成功帮我换源...\n    validations:\n      required: true\n\n  - type: input\n    id: version\n    attributes:\n      label: chsrc 版本\n      # description: 你正在使用 chsrc 哪个版本？\n      placeholder: 请使用 chsrc -h 或 chsrc -v 查看，并*复制发布日期*\n    validations:\n      required: true\n\n  - type: dropdown\n    id: os\n    attributes:\n      label: 你使用的是哪个操作系统？\n      multiple: true\n      options:\n        - Windows\n        - Linux\n        - macOS\n        - FreeBSD\n        - NetBSD\n        - OpenBSD\n        - 其他\n    validations:\n      required: true\n\n  - type: input\n    id: os-version\n    attributes:\n      label: OS 版本 / OS 发行版\n      # description: \"\"\n      placeholder: \"请告诉我们具体的OS版本或发行版，如 Windows 11, Ubuntu Linux 24.04... 等等\"\n    validations:\n      required: false\n\n  - type: textarea\n    id: logs\n    attributes:\n      label: Log 输出\n      description: 请复制粘贴任何相关的 Log 输出。此内容将自动格式化为代码块，因此不需要反引号\n      render: shell\n\n  - type: checkboxes\n    id: terms\n    attributes:\n      label: 防止重复问题\n      description: 请确认在打开这个新的 issue 之前已经搜索过类似的issue。你可以评论或订阅已经存在的相关 issue\n      options:\n        - label: 我已在项目中搜索过类似的 issue\n          required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/02-Request_Recipe.yml",
    "content": "name: 🫡 我想要对 target 换源!\ndescription: 想要对尚未支持的 target 进行换源？\ntitle: \"提前找好方案怎么换源是chsrc用户的一大美德\"\n# labels: [ ]\ntype: Request\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        请先回答这些问题\n\n  - type: textarea\n    id: description\n    attributes:\n      label: 描述新的换源目标\n      placeholder: 它是编程语言、操作系统还是一个普通软件？\n    validations:\n      required: true\n\n  - type: textarea\n    id: reference-solution\n    attributes:\n      label: 请尽可能提供可参考的换源方法\n      placeholder: 往往提供该源的镜像站会附带换源方法，可以提供给我们参考\n    validations:\n      required: true\n\n  - type: textarea\n    id: mirrors\n    attributes:\n      label: 请尽可能提供已有镜像站\n      placeholder: 当你提出该请求的时候，你可能已有心仪的镜像站，请告诉我们以避免重复查找劳动\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/03-Share.yml",
    "content": "name: 🎉 我找到了新的镜像站或源！\ndescription: 为大家分享新的镜像站或可用源！\ntitle: \"分享是chsrc用户的一大美德\"\n# labels: [ ]\ntype: Contribute\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        感谢你的分享！这将使你与更广大的用户得到更多可选的服务！同时也让镜像站开发维护人员更加有使命感！\n\n  - type: textarea\n    id: description\n    attributes:\n      label: 描述该镜像站或该源\n      description: |\n        1. 请告诉我们该镜像站的主体URL\n        2. 你是否已经测试过该镜像站的可用性？\n        3. 它大概提供哪些源？\n        4. 你想要我们为你添加该镜像站的具体哪个源？\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/04-Deprecate.yml",
    "content": "name: ⛓️‍💥 镜像源已失效\ndescription: 该镜像站已关停/该源已不再被支持\ntitle: \"报告镜像源情况是chsrc用户的一大美德\"\n# labels: [ ]\ntype: Deprecate\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        感谢你的一手消息！让用户不再疑惑是哪里出了错！\n\n  - type: textarea\n    id: description\n    attributes:\n      label: 什么被弃用了？\n      description: |\n        1. 请告诉我们是镜像站还是某个源失效\n        2. 如果可能，你可以开启该issue后参与维护！在代码中删除掉该源并不复杂！\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: true\ncontact_links:\n  - name: ❤️ 赞赏支持 chsrc\n    url: https://afdian.com/a/ccmywish\n    # about 不支持 Markdown 语法\n    about: 你是否因为 chsrc 而受到启发、节省了时间精力 or whatever?\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Add_Feature.md",
    "content": "## 新功能描述\n\n请描述该新功能，为什么要增加这个功能，以及具体的用例\n\n---\n\n## 方案\n\n请介绍你新增加该功能的方案\n\n---\n\n## 实现\n\n请介绍你的实现（若实现相当直接则不需要描述）\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Clean.md",
    "content": "## 描述\n\n注意: 小改动请使用该PR模板。而中等、大型规模的变化，或者引起巨大联动变化的改动，需要使用 `Refactor` PR模板。\n\n请介绍你进行了什么清理，如某部分代码，如某部分文档\n\n---\n\n## 方案\n\n请介绍你进行清理的方案（如果你认为有必要的话）\n\n---\n\n## 实现\n\n请介绍你的实现（若实现相当直接则不需要描述）\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Enhance.md",
    "content": "## 改进描述\n\n请描述要改进的具体内容，为什么要增强/改善它，以及具体的用例\n\n---\n\n## 方案\n\n请介绍你的改进方案\n\n---\n\n## 实现\n\n请介绍你的实现（若实现相当直接则不需要描述）\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Fix_Bug.md",
    "content": "## Bug 背景\n\n请介绍 Bug 的背景以及相关 issue\n\n---\n\n## Bug 原因\n\n请描述导致 Bug 的具体原因\n\n---\n\n## 方案\n\n请介绍你的修复方案\n\n---\n\n## 实现\n\n请介绍你的实现（若实现相当直接则不需要描述）\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Implement.md",
    "content": "## 问题描述\n\n(此内容必填)\n\n1. 简要说明此 PR 修复的具体问题或改进的功能背景\n2. 列出与此 PR 相关的 issue 或任务，若没有填 `N/A`\n\n<br>\n\n\n\n## 方案\n\n(此内容必填)\n\n详细描述针对该问题或功能改进的解决方案\n\n<br>\n\n\n\n## 实现\n\n(此内容可选填)\n\n在按照上述方案实现时，若遇到需记录和提醒他人的细节时，务必在此描述\n\n<br>\n\n\n\n## 测试\n\n(此内容可选填)\n\n描述如何验证本 PR，列出具体的测试步骤\n\n<br>\n\n\n\n## 备注\n\n(此内容可选填)\n\n列出需要特别注意或额外注意的事项\n\n<br>\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Refactor.md",
    "content": "## 背景\n\n注意: 中等、大型规模的变化，或者引起巨大联动变化的改动，才需要使用该模板。中小改动请使用 `Clean` PR模板。\n\n请介绍该重构的背景，可以带来哪些优势？\n\n---\n\n## 方案\n\n请介绍你进行重构的方案\n\n---\n\n## 实现\n\n请介绍你的实现（若实现相当直接则不需要描述）\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Relate_Mirror_Source.md",
    "content": "## 可用性确认\n\n1. 请你本人确认这些源真的可用或已经失效，不要等待其它用户帮你测试\n\n2. 请确保修改后代码依然可以编译及运行\n\n3. 请在你修改的各个文件的标头部分增加你自己的贡献信息，名字栏需要为中文拼音、或者英文名、或者账号名\n"
  },
  {
    "path": ".github/READIT.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : (Overview .github) READIT.md\n ! Doc Authors   : 曾奥然 <ccmywish@qq.com>\n ! Contributors  : Nul None <nul@none.org>\n !               |\n ! Created On    : <2025-06-20>\n ! Last Modified : <2025-06-20>\n !\n ! 此文件不能叫做 README.md，否则 GitHub 主页会显示此文件\n ! ---------------------------------------------------------- -->\n\n[`pull_request_template.md`](./pull_request_template.md) 是 [`PULL_REQUEST_TEMPLATE/Implement.md`](./PULL_REQUEST_TEMPLATE/Implement.md) 的最简化版\n"
  },
  {
    "path": ".github/copilot-instructions.md",
    "content": "# chsrc Project Rules for AI Assistants\n\n## 项目概述\n\n这是 chsrc 项目，一个用 C 语言编写的跨平台命令行换源工具，帮助用户在不同的镜像之间切换，适用于编程语言、操作系统、其他软件。它的最强大之处在于它是一个框架，能够帮助用户轻松地为不同的目标换源。\n\n\n## 架构\n\n- **Framework**: 在目录 `src/framework/` 中，包含了核心实现，支持 recipe\n\n  - `struct.h` 里定义了各种数据结构和宏，这是整个 chsrc 的核心，也是 chef DSL 的核心\n  - `chef.c` 里实现了 chef DSL，你可以使用它来确定正确的使用方法\n\n- **Recipes**: 在目录 `src/recipe/` 中，包含了针对不同目标的具体实现\n\n  - `lang/` - 编程语言 (Ruby, JavaScript 等等)\n  - `os/`   - 操作系统 (Ubuntu, Arch Linux 等等)\n  - `ware/` - 软件工具和应用 (Docker, Homebrew 等等)\n\n\n## Coding Guidelines\n\n### C Coding Style:\n\n请阅读 `doc/03-为什么拒绝使用代码格式化工具.md`\n\n### Important Project Concepts:\n\n请阅读 `doc/10-如何编写recipe.md`\n\n## Important: 一定要保持注释，因为它记录了重要的维护信息\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: github-actions\n    directory: \"/\"\n    schedule:\n      interval: weekly\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "## 问题描述\n\n1. 简要说明此 PR 修复的具体问题或改进的功能背景\n2. 列出与此 PR 相关的 issue 或任务，若没有填 `N/A`\n\n<br>\n\n\n\n## 方案与实现\n\n详细描述针对该问题或功能改进的解决方案\n\n<br>\n"
  },
  {
    "path": ".github/workflows/PR-notify.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : PR-notify.yml\n# File Authors  : 曾奥然 <ccmywish@qq.com>\n# Contributors  : Nul None <nul@none.org>\n#               |\n# Created On    : <2025-06-19>\n# Last Modified : <2025-08-07>\n#\n# Notify PR\n# ---------------------------------------------------------------\n\nname: 告知PR者\n\non:\n  pull_request_target:\n    types: [opened,\n            ready_for_review, # draft PR 转为正式 PR\n            review_requested,\n            reopened]\n\njobs:\n  enforce-dev-branch:\n    name: 强制使用dev分支\n    runs-on: ubuntu-latest\n    # github.event.pull_request_target 内容为空，转而用 pull_request\n    if: github.event.pull_request.base.ref != 'dev'\n    steps:\n      - name: 评论\n        uses: thollander/actions-comment-pull-request@v3\n        with:\n          message: |\n            Hi @${{github.event.pull_request.user.login}},\n\n            ❤️ 感谢你的贡献！你的 PR 当前基于 `${{github.base_ref}}` 分支，请修改使用 `dev` 分支\n          comment-tag: \"❤️ 感谢你的贡献！\"\n      - run: |\n          echo \"::error::❌ PR 必须以 dev 分支为目标！当前是 ${GITHUB_BASE_REF}\"\n          exit 1\n\n  welcome:\n    name: 欢迎PR者\n    runs-on: ubuntu-latest\n    # 仅在 opened 时欢迎，其他情况都不再重复欢迎了\n    if: github.event.pull_request.base.ref == 'dev' && github.event.action == 'opened'\n    steps:\n      - name: 查看 GitHub Actions 环境\n        run: |\n          echo \"Event 类型: ${{ github.event.action }}\"\n          echo \"Event 名: ${{ github.event_name }}\"\n\n      # 2025-10-06 移除点赞的步骤\n      # 因原 peter-evans/create-or-update-comment@v5 已不再支持空body，而如果使用 Github Token 之类又过于大材小用因此移除\n\n      - name: 添加评论欢迎 PRer\n        uses: peter-evans/create-or-update-comment@v5\n        with:\n          issue-number: ${{ github.event.pull_request.number }}\n          body: |\n            Hi @${{github.event.pull_request.user.login}}\n\n            ❤️ 感谢你的贡献！我们将在最少半小时，最多5天内阅读此 PR 并回复你\n          edit-mode: replace\n"
  },
  {
    "path": ".github/workflows/PR-test.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : PR-test.yml\n# File Authors  : 曾奥然 <ccmywish@qq.com>\n# Contributors  : Mikachu2333 <mikachu2333@zohomail.com>\n#               |\n# Created On    : <2025-06-19>\n# Last Modified : <2025-08-17>\n#\n# Test PR\n# ---------------------------------------------------------------\n\nname: 测试PR\n\non:\n  pull_request:\n    # 仅在开 pr、草稿转正式、手动要求 review、reopen的时候运行测试\n    types: [\n        opened,\n        # 因 synchronize 将导致 pr 的构建过于频繁而禁用\n        # synchronize, # 在 pr 者 push commit 时每次构建\n        ready_for_review, # draft PR 转为正式 PR\n        review_requested,\n        reopened,\n      ]\n    paths:\n      - \"src/**\"\n      - \"lib/**\"\n\njobs:\n  test-on-ubuntu:\n    name: 在Ubuntu上测试\n    runs-on: ubuntu-latest\n    if: github.event.pull_request.base.ref == 'dev'\n\n    steps:\n      - name: 检出代码\n        uses: actions/checkout@v6\n\n      - name: 测试构建情况\n        run: |\n          make\n\n      - name: 测试test情况\n        run: |\n          make test\n\n  test-on-windows:\n    name: 在Windows上测试\n    runs-on: windows-latest\n    if: github.event.pull_request.base.ref == 'dev'\n\n    steps:\n      - name: 检出代码\n        uses: actions/checkout@v6\n\n      - name: 创建测试文件\n        shell: powershell\n        run: |\n          New-Item -Path \"$env:USERPROFILE\\Documents\\Powershell\\Microsoft.PowerShell_profile.ps1\" -ItemType File -Force\n          New-Item -Path \"$env:USERPROFILE\\Documents\\WindowsPowerShell\\Microsoft.PowerShell_profile.ps1\" -ItemType File -Force\n\n      - name: 安装依赖\n        run: |\n          choco install just\n\n      - name: 测试构建情况\n        run: |\n          just\n\n      - name: 测试test情况\n        run: |\n          just test\n"
  },
  {
    "path": ".github/workflows/build-on-Linux-AArch64.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : build-on-Linux-AArch64.yml\n# File Authors  : 曾奥然 <ccmywish@qq.com>\n# Contributors  : Nul None <nul@none.org>\n#               |\n# Created On    : <2023-09-14>\n# Last Modified : <2025-09-12>\n#\n# Build chsrc on Linux (AArch64) and upload it to GitHub: the 'pre' release\n# ---------------------------------------------------------------\n\nname: 构建于 Linux AArch64\non:\n  push:\n    branches: [ \"gh-build\" ]\n\njobs:\n  build-and-upload:\n    runs-on: ubuntu-latest\n    steps:\n      - name: 构建\n        uses: uraimo/run-on-arch-action@v3\n        with:\n          arch: aarch64\n          distro: ubuntu_latest\n\n          dockerRunArgs: |\n            --volume \"${PWD}/artifacts:/artifacts\"\n          run: |\n            apt-get update -qq\n            apt-get install build-essential -y -q\n            apt-get install git -y -q\n            pwd ; ls -al\n            git clone https://github.com/RubyMetric/chsrc -b gh-build -q\n            cd chsrc\n\n            make build-in-ci-release-mode\n            mv chsrc-ci-release chsrc-aarch64-linux\n\n            cp ./chsrc-aarch64-linux /artifacts\n\n      - name: 上传至 'pre' release\n        uses: softprops/action-gh-release@v2\n        with:\n          tag_name: pre\n          files: |\n            ./artifacts/chsrc-aarch64-linux\n"
  },
  {
    "path": ".github/workflows/build-on-Linux-ARMv7.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : build-on-Linux-ARMv7.yml\n# File Authors  : 曾奥然 <ccmywish@qq.com>\n# Contributors  : Nul None <nul@none.org>\n#               |\n# Created On    : <2023-09-14>\n# Last Modified : <2025-09-12>\n#\n# Build chsrc on Linux (ARMv7) and upload it to GitHub: the 'pre' release\n# ---------------------------------------------------------------\n\nname: 构建于 Linux ARMv7\non:\n  push:\n    branches: [ \"gh-build\" ]\n\njobs:\n  build-and-upload:\n    runs-on: ubuntu-latest\n    steps:\n      - name: 构建\n        uses: uraimo/run-on-arch-action@v3\n        with:\n          arch: armv7\n          distro: ubuntu_latest\n\n          dockerRunArgs: |\n            --volume \"${PWD}/artifacts:/artifacts\"\n          run: |\n            apt-get update -qq\n            apt-get install build-essential -y -q\n            apt-get install git -y -q\n            pwd ; ls -al\n            git clone https://github.com/RubyMetric/chsrc -b gh-build -q\n            cd chsrc\n\n            make build-in-ci-release-mode\n            mv chsrc-ci-release chsrc-armv7-linux\n\n            cp ./chsrc-armv7-linux /artifacts\n\n      - name: 上传至 'pre' release\n        uses: softprops/action-gh-release@v2\n        with:\n          tag_name: pre\n          files: |\n            ./artifacts/chsrc-armv7-linux\n"
  },
  {
    "path": ".github/workflows/build-on-Linux-riscv64.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : build-on-Linux-riscv64.yml\n# File Authors  : 曾奥然 <ccmywish@qq.com>\n# Contributors  : Nul None <nul@none.org>\n#               |\n# Created On    : <2023-09-14>\n# Last Modified : <2025-09-12>\n#\n# Build chsrc on Linux (riscv64) and upload it to GitHub: the 'pre' release\n# ---------------------------------------------------------------\n\nname: 构建于 Linux riscv64\non:\n  push:\n    branches: [ \"gh-build\" ]\n\njobs:\n  build-and-upload:\n    runs-on: ubuntu-latest\n    steps:\n      - name: 构建\n        uses: uraimo/run-on-arch-action@v3\n        with:\n          arch: riscv64\n          distro: ubuntu_latest\n\n          dockerRunArgs: |\n            --volume \"${PWD}/artifacts:/artifacts\"\n          run: |\n            apt-get update -qq\n            apt-get install build-essential -y -q\n            apt-get install git -y -q\n            pwd ; ls -al\n            git clone https://github.com/RubyMetric/chsrc -b gh-build -q\n            cd chsrc\n\n            make build-in-ci-release-mode\n            mv chsrc-ci-release chsrc-riscv64-linux\n\n            cp ./chsrc-riscv64-linux /artifacts\n\n      - name: 上传至 'pre' release\n        uses: softprops/action-gh-release@v2\n        with:\n          tag_name: pre\n          files: |\n            ./artifacts/chsrc-riscv64-linux\n"
  },
  {
    "path": ".github/workflows/build-on-Linux-x64.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : build-on-Linux-x64.yml\n# File Authors  : 曾奥然 <ccmywish@qq.com>\n# Contributors  : Nul None <nul@none.org>\n#               |\n# Created On    : <2023-09-14>\n# Last Modified : <2025-09-12>\n#\n# Build chsrc on Linux (x64) and upload it to GitHub: the 'pre' release\n# ---------------------------------------------------------------\n\nname: 构建于 Linux x64\non:\n  push:\n    branches: [ \"gh-build\" ]\n\njobs:\n  build-and-upload:\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: 检出代码\n      uses: actions/checkout@v6\n\n    - name: 构建\n      run: |\n        make build-in-ci-release-mode\n        mv chsrc-ci-release chsrc-x64-linux\n\n    - name: List files\n      run: ls *-linux\n\n    - name: 上传至 'pre' release\n      uses: softprops/action-gh-release@v2\n      # if: startsWith(github.ref, 'refs/tags/')\n      with:\n        tag_name: pre\n        files: |\n          chsrc-x64-linux\n"
  },
  {
    "path": ".github/workflows/build-on-Windows.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : build-on-Windows.yml\n# File Authors  : 曾奥然 <ccmywish@qq.com>\n# Contributors  : Nul None <nul@none.org>\n#               |\n# Created On    : <2023-09-14>\n# Last Modified : <2025-09-12>\n#\n# Build chsrc on Windows and upload it to GitHub: the 'pre' release\n# ---------------------------------------------------------------\n\nname: 构建于 Windows\non:\n  push:\n    branches: [ \"gh-build\" ]\n\njobs:\n  build-and-upload:\n    runs-on: windows-latest\n    defaults:\n      run:\n        shell: msys2 {0}\n\n    steps:\n\n    - name: 检出代码\n      uses: actions/checkout@v6\n\n    - name: 安装 GCC\n      uses: msys2/setup-msys2@v2\n      with:\n        msystem: UCRT64\n        update: true\n        install: |\n          mingw-w64-ucrt-x86_64-gcc\n          mingw-w64-ucrt-x86_64-make\n          mingw-w64-i686-gcc\n          mingw-w64-i686-make\n\n    - name: 为 x64 构建\n      run: |\n        mingw32-make.exe build-in-ci-release-mode\n        mv chsrc-ci-release.exe chsrc-x64-windows.exe\n\n    - name: 为 x32 构建\n      env:\n        MSYSTEM: MINGW32\n      run: |\n        mingw32-make.exe build-in-ci-release-mode\n        mv chsrc-ci-release.exe chsrc-x86-windows.exe\n\n    - name: 为 Android 构建\n      run: |\n        compiler=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android21-clang\n\n        # 检查编译器版本\n        $compiler --version\n        echo\n\n        mingw32-make.exe build-in-ci-release-mode CC=$compiler CROSS_BUILD_WINDOWS_FOR_ANDROID=1\n        echo\n\n        # 让我们看看里面有啥\n        ls\n        echo\n\n        mv chsrc-ci-release chsrc-arm64-android\n\n    - name: List files\n      run: ls *.exe\n\n    - name: 上传至 'pre' release\n      uses: softprops/action-gh-release@v2\n      # if: startsWith(github.ref, 'refs/tags/')\n      with:\n        tag_name: pre\n        files: |\n          chsrc-x64-windows.exe\n          chsrc-x86-windows.exe\n          chsrc-arm64-android\n"
  },
  {
    "path": ".github/workflows/build-on-macOS.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : build-on-macOS.yml\n# File Authors  : 曾奥然 <ccmywish@qq.com>\n# Contributors  : Nul None <nul@none.org>\n#               |\n# Created On    : <2023-09-15>\n# Last Modified : <2025-12-18>\n#\n# Build chsrc on macOS and upload it to GitHub: the 'pre' release\n# ---------------------------------------------------------------\n\nname: 构建于 macOS\non:\n  push:\n    branches: [ \"gh-build\" ]\n\njobs:\n  on-arm64:\n    runs-on: macos-latest\n\n    steps:\n    - name: 检出代码\n      uses: actions/checkout@v6\n\n    - name: 检查编译器版本\n      run: |\n        clang --version\n        echo\n        gcc --version\n        echo\n        gcc-14 --version\n\n    - name: 为 arm64 (AArch64) 构建\n      run: |\n        make build-in-ci-release-mode\n        mv chsrc-ci-release chsrc-aarch64-macos\n\n    - name: List files\n      run: ls *-macos\n\n    - name: 上传至 'pre' release\n      uses: softprops/action-gh-release@v2\n      # if: startsWith(github.ref, 'refs/tags/')\n      with:\n        tag_name: pre\n        files: |\n          chsrc-aarch64-macos\n\n\n  on-x64:\n    # macos-13 是 x64，macos-14 是 AArch64(ARMv8-A)\n    # 但是 macos-13 已经于 2025-12-04 下线\n    runs-on: macos-15-intel\n\n    steps:\n    - name: 检出代码\n      uses: actions/checkout@v6\n\n    - name: 检查编译器版本\n      run: |\n        clang --version\n        echo\n        gcc --version\n        echo\n        gcc-14 --version\n\n    - name: 为 x64 构建\n      run: |\n        make build-in-ci-release-mode\n        mv chsrc-ci-release chsrc-x64-macos\n\n    - name: List files\n      run: ls *-macos\n\n    - name: 上传至 'pre' release\n      uses: softprops/action-gh-release@v2\n      # if: startsWith(github.ref, 'refs/tags/')\n      with:\n        tag_name: pre\n        files: |\n          chsrc-x64-macos\n"
  },
  {
    "path": ".github/workflows/pkg-deb.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : pkg-deb.yml\n# File Authors  : sanchuanhehe <wyihe5520@gmail.com>\n# Contributors  : 曾奥然 <ccmywish@qq.com>\n#               |\n# Created On    : <2025-06-10>\n# Last Modified : <2025-10-29>\n#\n# Build and publish deb packages\n# ---------------------------------------------------------------\n\nname: 构建发布deb包\n\non:\n  release:\n    types: [ released ]\n  push:\n    branches: [ \"gh-build\" ]\n  workflow_dispatch:\n    inputs:\n      version:\n        description: 'Version to build'\n        required: true\n        default: '0.3.0'  # 短暂时间内不可达到的最新版本号\n\njobs:\n  Build-deb:\n    name: 构建deb包\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: 检出代码\n      uses: actions/checkout@v6\n      with:\n        ref: gh-build\n\n    - name: 获取版本号\n      id: get_version\n      run: |\n        if [ \"${{ github.event_name }}\" = \"release\" ]; then\n          version=\"${{ github.event.release.tag_name }}\"\n          # 删除前缀 'v' if present\n          version=${version#v}\n\n        elif [ \"${{ github.event_name }}\" = \"push\" ];then\n          # 从源代码中提取版本号\n          version=$(sed -E -n 's/^#define Chsrc_Version +\"([0-9]+\\.[0-9]+\\.[0-9]+).*\"/\\1/p' ./src/framework/version.h)\n\n        else\n          version=\"${{ github.event.inputs.version }}\"\n        fi\n\n        echo \"version=$version\" >> $GITHUB_OUTPUT\n        echo \"Version: $version\"\n\n    - name: 验证版本号\n      run: |\n        version=\"${{ steps.get_version.outputs.version }}\"\n\n        if [[ ! $version =~ ^[0-9]+\\.[0-9]+\\.[0-9]+$ ]]; then\n          echo \"Invalid version format: $version\"\n          exit 1\n        fi\n\n    - name: 更新 debian/changelog\n      run: |\n        version=\"${{ steps.get_version.outputs.version }}\"\n\n        cd ./pkg/deb\n\n        (cat << EOF; cat ./debian/changelog) > new_changelog\n        chsrc ($version-1) unstable; urgency=medium\n\n          * Release version $version\n\n         -- 曾奥然 <ccmywish@qq.com>  $(date -R)\n\n        EOF\n\n        mv -f new_changelog ./debian/changelog\n\n    - name: 安装构建依赖\n      run: |\n        sudo apt-get update\n        sudo apt-get install -y debhelper devscripts build-essential fakeroot\n\n    - name: 构建\n      run: |\n        make build-deb\n\n    - name: 移动构建产物到./dist和./dist-for-pre\n      run: |\n        version=\"${{ steps.get_version.outputs.version }}\"\n\n        # 创建两个目录来存放构建产物（产物内容一样，只是文件名不一样）\n        mkdir dist dist-for-pre\n        find ./pkg -name \"chsrc_${version}*.deb\" -exec mv {} dist/ \\;\n        cp -r dist/* dist-for-pre/\n\n        # 上传至 'pre' release 的文件名需要设置为 'latest', 从而稳定下载URL\n        cd ./dist-for-pre\n        for old_name in ./chsrc_${version}*.deb; do\n          new_name=\"${old_name/${version}-1/latest-1}\"\n          mv \"$old_name\" \"$new_name\"\n        done\n\n    - name: 验证生成的deb包\n      run: |\n        version=\"${{ steps.get_version.outputs.version }}\"\n        ls -la dist/\n        dpkg-deb --info dist/chsrc_${version}-1_amd64.deb\n        dpkg-deb --contents dist/chsrc_${version}-1_amd64.deb\n\n    - name: 测试deb包能否正常安装\n      run: |\n        version=\"${{ steps.get_version.outputs.version }}\"\n\n        sudo dpkg -i dist/chsrc_${version}-1_amd64.deb || true\n        sudo apt-get install -f -y || true\n\n        bash pkg/deb/deb-installation-test.sh\n\n    - name: 上传deb包到artifacts\n      uses: actions/upload-artifact@v6\n      with:\n        name: chsrc-deb-files\n        path: dist/chsrc_*.deb\n        retention-days: 30\n\n    - name: 上传附件到GitHub Releases(the newly created release)\n      if: github.event_name == 'release'\n      uses: softprops/action-gh-release@v2\n      with:\n        # 用 * 省略版本号，以及指代各种架构\n        files: dist/chsrc_*.deb\n\n    - name: 上传附件到GitHub Releases(the 'pre' release)\n      if: github.event_name == 'push'\n      uses: softprops/action-gh-release@v2\n      with:\n        tag_name: pre\n        # 用 * 指代各种架构\n        files: dist-for-pre/chsrc_latest-1_*.deb\n\n\n\n\n\n  Create-APT-repository:\n    name: 创建APT仓库\n    needs: Build-deb\n    runs-on: ubuntu-latest\n    if: github.event_name == 'release'\n\n    steps:\n    - name: Download all artifacts\n      uses: actions/download-artifact@v7\n      with:\n        pattern: chsrc-deb-files\n        merge-multiple: true\n        path: ./debs\n\n    - name: Install repository tools\n      run: |\n        sudo apt-get update\n        sudo apt-get install -y dpkg-dev\n\n    - name: Create Packages file\n      run: |\n        cd debs\n        dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz\n        dpkg-scanpackages . /dev/null > Packages\n\n    - name: Upload repository metadata\n      uses: actions/upload-artifact@v6\n      with:\n        name: debian-repository-metadata\n        path: debs/Packages*\n        retention-days: 30\n"
  },
  {
    "path": ".github/workflows/pub-AUR-chsrc-and-chsrc-bin.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : pub-AUR-chsrc-and-chsrc-bin.yml\n# File Authors  : Terrasse <terrasse@qq.com>\n# Contributors  : Nul None <nul@none.org>\n#               |\n# Created On    : <2024-08-29>\n# Last Modified : <2025-03-18>\n#\n# Publish the 2 packages to AUR when a new release is created:\n#   1. chsrc\n#   2. chsrc-bin\n#\n# Note: only normal version tags like 'v1.2.3' will be published\n# ---------------------------------------------------------------\n\nname: Publish 'chsrc' and 'chsrc-bin' to AUR\non:\n  release:\n    types: [ released ]\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Get the release tag\n      id: get_tag\n      run: |\n        echo \"tag=${GITHUB_REF#refs/*/}\" >> $GITHUB_ENV\n    - name: Validate version tag\n      run: |\n        if [[ ! $tag =~ ^v[0-9]+\\.[0-9]+\\.[0-9]+$ ]]; then\n          echo \"Abnormal version tag: $tag\"\n          echo \"valid=0\" >> $GITHUB_ENV\n        else\n          version=$(echo $tag | sed 's/^v//')\n          echo \"version=$version\" >> $GITHUB_ENV\n          echo \"valid=1\" >> $GITHUB_ENV\n        fi\n    - name: Fetch PKGBUILD\n      run: |\n        wget https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD\\?h\\=chsrc-bin -O ./PKGBUILD_bin\n    - name: Update PKGBUILD\n      run: |\n        sed -i \"s/pkgver=.*/pkgver=$version/\" PKGBUILD_bin\n    - name: Publish chsrc-bin to AUR\n      if: env.valid == '1'\n      uses: KSXGitHub/github-actions-deploy-aur@v4.1.1\n      with:\n        pkgname: chsrc-bin\n        pkgbuild: ./PKGBUILD_bin\n        updpkgsums: true\n        test: true # Check that PKGBUILD could be built, and update pkgver\n        commit_username: ${{ secrets.AUR_USERNAME }}\n        commit_email: ${{ secrets.AUR_EMAIL }}\n        ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}\n        commit_message: \"github-action-auto-publish v${{ env.version }}\"\n    - name: Fetch PKGBUILD\n      run: |\n        wget https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD\\?h\\=chsrc -O ./PKGBUILD\n    - name: Update PKGBUILD\n      run: |\n        sed -i \"s/pkgver=.*/pkgver=$version/\" PKGBUILD\n    - name: Publish chsrc to AUR\n      if: env.valid == '1'\n      uses: KSXGitHub/github-actions-deploy-aur@v4.1.1\n      with:\n        pkgname: chsrc\n        pkgbuild: ./PKGBUILD\n        updpkgsums: true\n        test: true # Check that PKGBUILD could be built, and update pkgver\n        commit_username: ${{ secrets.AUR_USERNAME }}\n        commit_email: ${{ secrets.AUR_EMAIL }}\n        ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}\n        commit_message: \"github-action-auto-publish v${{ env.version }}\"\n"
  },
  {
    "path": ".github/workflows/pub-AUR-chsrc-git.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : pub-AUR-chsrc-git.yml\n# File Authors  : Terrasse <terrasse@qq.com>\n# Contributors  : Nul None <nul@none.org>\n#               |\n# Created On    : <2024-08-29>\n# Last Modified : <2025-06-19>\n#\n# Publish package 'chsrc-git' to AUR when branch 'main' is updated.\n# ---------------------------------------------------------------\n\nname: Publish 'chsrc-git' to AUR\non:\n  workflow_dispatch:\n  push:\n    branches: [ \"main\" ] # chsrc-git syncs with main\n    paths:\n      - \"src/**\"\n      - \"lib/**\"\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Fetch PKGBUILD\n      run: |\n        wget https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD\\?h\\=chsrc-git -O ./PKGBUILD\n    - name: Publish to AUR\n      uses: KSXGitHub/github-actions-deploy-aur@v4.1.1\n      with:\n        pkgname: chsrc-git\n        pkgbuild: ./PKGBUILD\n        test: true # Check that PKGBUILD could be built, and update pkgver\n        commit_username: ${{ secrets.AUR_USERNAME }}\n        commit_email: ${{ secrets.AUR_EMAIL }}\n        ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}\n        commit_message: \"github-action-auto-publish\\n${{ github.sha }}\"\n"
  },
  {
    "path": ".github/workflows/pub-WinGet.yml",
    "content": "# ---------------------------------------------------------------\n# Workflow File : pub-WinGet.yml\n# File Authors  :   YU-7   <2747046473@qq.com>\n# Contributors  : Nul None <nul@none.org>\n#               |\n# Created On    : <2024-12-25>\n# Last Modified : <2024-12-25>\n#\n# This workflow publish to winget\n# ---------------------------------------------------------------\n\nname: Publish to WinGet\non:\n  release:\n    types: [released]\njobs:\n  publish:\n    runs-on: windows-latest\n    steps:\n      - uses: vedantmgoyal9/winget-releaser@main\n        with:\n          identifier:  RubyMetric.chsrc\n          installers-regex: '\\.exe$' # Only .exe files\n          token: ${{ secrets.WINGET_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "##############################\n#          VS Code\n##############################\n.vscode/*\n!.vscode/extensions.json\n!.vscode/settings.json\n!.vscode/c_cpp_properties.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/README.md\n\n\n##############################\n#            VS\n##############################\n.vs\n\n\n##############################\n#         Binaries\n##############################\n*.o\n*.obj\n*.a\n*.lib\n*.so\n*.dll\n*.out\n*.exe\n*.res\n\n\n##############################\n#      Built executables\n##############################\nchsrc\nchsrc-debug\nchsrc-release\nchsrc-ci-release\n\n\n\n##############################\n#        Test files\n##############################\nxy\nfw\nREADME.md.bak*\n*.tmp\nchsrc_tmp_test.txt\nchsrc_tmp_test.txt.bak\n\n# Generated when testing (when there's a bug)\nnul\n\n# 'chsrc set -scope=project' generated\n.bundle\n.npmrc\n\n\n\n##############################\n#          Texinfo\n##############################\nchsrc.aux\nchsrc.log\nchsrc.toc\n*.info\n*.pdf\n\n\n\n##############################\n#         deb package\n##############################\n# deb package 未归档的目录\npkg/deb/debian/chsrc/\n\n# 下面这个目录包含创建出 $HOME 的虚拟环境\npkg/deb/debian/.debhelper/\n\npkg/deb/debian/debhelper-build-stamp\npkg/deb/debian/files\npkg/deb/debian/chsrc.debhelper.log\npkg/deb/debian/chsrc.substvars\n\n# 以下为 deb package 构建的直接产物\nchsrc_*.deb\nchsrc-dbgsym_*.ddeb\nchsrc_*.build\nchsrc_*.buildinfo\nchsrc_*.changes\n"
  },
  {
    "path": ".vscode/README.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : (for VS Code users) README.md\n ! Doc Authors   : 曾奥然 <ccmywish@qq.com>\n ! Contributors  : Nul None <nul@none.org>\n !               |\n ! Created On    : <2025-06-18>\n ! Last Modified : <2025-06-20>\n ! ---------------------------------------------------------- -->\n\n# Dev in VS Code\n\n首先需要安装好 [just](https://github.com/casey/just)，而不再硬性需要 `make`\n\n1. `Ctrl-Shift-B` 直接构建\n2. `F5` 直接开始 Debug\n"
  },
  {
    "path": ".vscode/c_cpp_properties.json",
    "content": "{\n    \"configurations\": [\n        {\n            \"name\": \"Win32\",\n            \"includePath\": [\n                \"${workspaceFolder}/**\"\n            ],\n            \"cStandard\": \"c17\",\n            \"intelliSenseMode\": \"windows-gcc-x64\"\n        },\n        {\n            \"name\": \"Linux\",\n            \"includePath\": [\n                \"${workspaceFolder}/**\"\n            ],\n            \"cStandard\": \"c17\"\n        },\n        {\n            \"name\": \"Mac\",\n            \"includePath\": [\n                \"${workspaceFolder}/**\"\n            ],\n            \"cStandard\": \"c17\"\n        }\n    ],\n    \"enableConfigurationSquiggles\": true,\n    \"version\": 4\n}\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n    \"recommendations\": [\n        \"ms-vscode.cpptools\",\n        \"ms-vscode.cpptools-extension-pack\",\n        \"editorconfig.editorconfig\",\n        \"redhat.vscode-yaml\",\n        \"nefrob.vscode-just-syntax\"\n    ],\n    \"unwantedRecommendations\": [\n        \"esbenp.prettier-vscode\"\n    ]\n}\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Debug chsrc\",\n            \"type\": \"cppdbg\",\n            \"request\": \"launch\",\n            \"program\": \"${workspaceFolder}/chsrc-debug\",\n            \"args\": [\n                \"get\",\n                \"nodejs\"\n            ],\n            \"preLaunchTask\": \"构建 debug 版 chsrc\",\n            \"stopAtEntry\": true,\n            \"cwd\": \"${workspaceFolder}\",\n            \"environment\": [],\n            // 如果你认为使用弹出窗口难以调试，可尝试设置为false\n            \"externalConsole\": true,\n            // lldb 等请自行设置，不作额外说明\n            \"MIMode\": \"gdb\",\n            // \"miDebuggerPath\": \"/path/to/gdb\",\n            \"setupCommands\": [\n                {\n                    \"description\": \"Enable pretty-printing for gdb\",\n                    \"text\": \"-enable-pretty-printing\",\n                    \"ignoreFailures\": true\n                },\n                {\n                    \"description\": \"Set Disassembly Flavor to Intel\",\n                    \"text\": \"-gdb-set disassembly-flavor intel\",\n                    \"ignoreFailures\": true\n                }\n            ],\n            \"postDebugTask\": \"停止 debug 程序\"\n        },\n\n        {\n            \"name\": \"Debug framework\",\n            \"type\": \"cppdbg\",\n            \"request\": \"launch\",\n            \"program\": \"${workspaceFolder}/fw\",\n            \"args\": [],\n            \"preLaunchTask\": \"测试 framework\",\n            \"stopAtEntry\": true,\n            \"cwd\": \"${workspaceFolder}\",\n            \"environment\": [],\n            \"externalConsole\": false,\n            \"MIMode\": \"gdb\",\n            // \"miDebuggerPath\": \"/path/to/gdb\",\n            \"setupCommands\": [\n                {\n                    \"description\": \"Enable pretty-printing for gdb\",\n                    \"text\": \"-enable-pretty-printing\",\n                    \"ignoreFailures\": true\n                },\n                {\n                    \"description\": \"Set Disassembly Flavor to Intel\",\n                    \"text\": \"-gdb-set disassembly-flavor intel\",\n                    \"ignoreFailures\": true\n                }\n            ]\n        }\n    ]\n}"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"editor.fontLigatures\": false,\n\n    \"C_Cpp.autoAddFileAssociations\": false,\n    \"C_Cpp.intelliSenseEngine\": \"Tag Parser\",\n    \"C_Cpp.default.browse.limitSymbolsToIncludedHeaders\": false,\n\n    \"editor.formatOnSave\": false,\n\n    \"C_Cpp.clang_format_fallbackStyle\": \"GNU\",\n    \"C_Cpp.formatting\": \"disabled\",\n\n    \"[c]\": {\n        \"editor.defaultFormatter\": null,\n    },\n    \"[h]\": {\n        \"editor.defaultFormatter\": null\n    },\n    \"[jsonc]\": {\n        \"editor.defaultFormatter\": \"vscode.json-language-features\"\n    },\n    \"[yaml]\": {\n        \"editor.defaultFormatter\": \"redhat.vscode-yaml\"\n    },\n\n    \"vscode-just.formatOnSave\": false,\n}\n"
  },
  {
    "path": ".vscode/tasks.json",
    "content": "{\n    \"tasks\": [\n        {\n            \"type\": \"shell\",\n            \"label\": \"构建 chsrc\",\n            \"command\": \"just\",\n            \"args\": [\n                \"build\"\n            ],\n            \"options\": {\n                \"cwd\": \"${workspaceFolder}\"\n            },\n            \"problemMatcher\": [\n                \"$gcc\"\n            ],\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": true\n            },\n            \"dependsOn\": \"停止程序\",\n            \"detail\": \"先停止原有程序，然后使用 just build 编译\"\n        },\n        {\n            \"type\": \"shell\",\n            \"label\": \"构建 debug 版 chsrc\",\n            \"command\": \"just\",\n            \"args\": [\n                \"build-in-debug-mode\"\n            ],\n            \"options\": {\n                \"cwd\": \"${workspaceFolder}\"\n            },\n            \"problemMatcher\": [\n                \"$gcc\"\n            ],\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": false\n            },\n        },\n        {\n            \"type\": \"shell\",\n            \"label\": \"测试 chsrc\",\n            \"command\": \"just\",\n            \"args\": [\n                \"test\"\n            ],\n            \"options\": {\n                \"cwd\": \"${workspaceFolder}\"\n            },\n            \"problemMatcher\": [\n                \"$gcc\"\n            ],\n            \"group\": {\n                \"kind\": \"test\",\n                \"isDefault\": true\n            },\n            \"detail\": \"使用 just test 测试\"\n        },\n        {\n            \"type\": \"shell\",\n            \"label\": \"测试 framework\",\n            \"command\": \"just\",\n            \"args\": [\n                \"test-fw\"\n            ],\n            \"options\": {\n                \"cwd\": \"${workspaceFolder}\"\n            },\n            \"problemMatcher\": [\n                \"$gcc\"\n            ],\n            \"group\": {\n                \"kind\": \"test\",\n                \"isDefault\": false\n            },\n            \"detail\": \"使用 just test-fw 测试 framework\"\n        },\n        {\n            \"type\": \"shell\",\n            \"label\": \"测试 xy.h\",\n            \"command\": \"just\",\n            \"args\": [\n                \"test-xy\"\n            ],\n            \"options\": {\n                \"cwd\": \"${workspaceFolder}\"\n            },\n            \"problemMatcher\": [\n                \"$gcc\"\n            ],\n            \"group\": {\n                \"kind\": \"test\",\n                \"isDefault\": false\n            },\n            \"detail\": \"使用 just test-xy 测试 xy.h\"\n        },\n        {\n            \"type\": \"shell\",\n            \"label\": \"停止 debug 程序\",\n            \"windows\": {\n                \"command\": \"powershell\",\n                \"args\": [\n                    \"-c\",\n                    \"Get-Process -Name \\\"chsrc-debug\\\" -ErrorAction SilentlyContinue | Stop-Process -Force;\",\n                    \"Get-Process -Name \\\"gdb\\\" -ErrorAction SilentlyContinue | Stop-Process -Force;\",\n                    \"Get-Process -Name \\\"WindowsDebugLauncher\\\" -ErrorAction SilentlyContinue | Stop-Process -Force;\"\n                ]\n            },\n            \"linux\": {\n                \"command\": \"bash\",\n                \"args\": [\n                    \"-c\",\n                    \"if pgrep -f chsrc-debug > /dev/null; then pkill -f chsrc-debug; fi\"\n                ]\n            },\n            \"osx\": {\n                \"command\": \"bash\",\n                \"args\": [\n                    \"-c\",\n                    \"if pgrep -f chsrc-debug > /dev/null; then pkill -f chsrc-debug; fi\"\n                ]\n            },\n            \"group\": \"build\",\n            \"presentation\": {\n                \"echo\": true,\n                \"reveal\": \"silent\",\n                \"focus\": false,\n                \"panel\": \"shared\",\n                \"showReuseMessage\": true,\n                \"clear\": false\n            },\n            \"detail\": \"停止 debug 版本的 chsrc\"\n        },\n        {\n            \"type\": \"shell\",\n            \"label\": \"停止程序\",\n            \"windows\": {\n                \"command\": \"powershell\",\n                \"args\": [\n                    \"-c\",\n                    \"Get-Process -Name \\\"chsrc\\\" -ErrorAction SilentlyContinue | Stop-Process -Force;\"\n                ]\n            },\n            \"linux\": {\n                \"command\": \"bash\",\n                \"args\": [\n                    \"-c\",\n                    \"if pgrep -f chsrc > /dev/null; then pkill -f chsrc; fi\"\n                ]\n            },\n            \"osx\": {\n                \"command\": \"bash\",\n                \"args\": [\n                    \"-c\",\n                    \"if pgrep -f chsrc > /dev/null; then pkill -f chsrc; fi\"\n                ]\n            },\n            \"group\": \"build\",\n            \"presentation\": {\n                \"echo\": true,\n                \"reveal\": \"always\",\n                \"focus\": false,\n                \"panel\": \"shared\",\n                \"showReuseMessage\": true,\n                \"clear\": false\n            },\n            \"detail\": \"跨平台停止 chsrc\"\n        }\n    ],\n    \"version\": \"2.0.0\"\n}"
  },
  {
    "path": "COPYING",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "LICENSE-MIT.txt",
    "content": "MIT License\n\nCopyright (c) 2023-2026 曾奥然 (Aoran Zeng), 郭恒 (Heng Guo)\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 (including the next paragraph) 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"
  },
  {
    "path": "Makefile",
    "content": "#!/usr/bin/make -f\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# --------------------------------------------------------------\n# Build File    : Makefile\n# File Authors  : 曾奥然 <ccmywish@qq.com>\n# Contributors  : Yangmoooo <yangmoooo@outlook.com>\n#\t\t\t\t\t\t\t\t| sanchuanhehe <wyihe5520@gmail.com>\n#\t\t\t\t\t\t\t\t|\n# Created On    : <2023-08-28>\n# Last Modified : <2025-10-15>\n#\n# 请阅读 ./doc/01-开发与构建.md 来使用\n# --------------------------------------------------------------\n\n#=========== OS Check ================\nOn-Linux = 0\nOn-Windows = 0\nOn-macOS = 0\n\nifeq ($(shell uname), Linux)\n\tOn-Linux = 1\nendif\n\nifeq ($(shell uname), Darwin)\n\tOn-macOS = 1\nendif\n\n# 只有 MSYS2 会定义 $(OS) 变量\nifeq ($(OS), Windows_NT)\n\tOn-Windows = 1\nendif\n# 注意, 原生 Windows 会定义 $(ComSpec) 变量，且区分大小写\n# 但是 MSYS2 并不会定义\n#=====================================\n\n\n\n#======== Default Tooling ============\nifeq ($(On-Windows), 1)\n  # MSYS2 环境\n\tCC = cc\nelse ifeq ($(On-macOS), 1)\n\tCC = clang\nelse\n\tCC = cc\nendif\n\nifeq ($(On-macOS), 1)\n\tDEBUGGER = lldb\nelse\n\tDEBUGGER = gdb\nendif\n#=====================================\n\n\n\n#======== Compilation Config ==========\nCFLAGS += -Iinclude -Ilib\n\nifeq ($(On-Windows), 1)\n\tCLANG_FLAGS = -target x86_64-pc-windows-gnu\nendif\n\nifeq ($(CC), clang)\n\tCFLAGS += $(CLANG_FLAGS)\nendif\n\noverride WARN += -Wall -Wextra -Wno-unused-variable -Wno-unused-function -Wno-missing-braces -Wno-misleading-indentation \\\n\t-Wno-missing-field-initializers -Wno-unused-parameter -Wno-sign-compare\n_C_Warning_Flags := $(WARN)\n\nDevMode-Target-Name = chsrc\nDebugMode-Target-Name = chsrc-debug\nReleaseMode-Target-Name = chsrc-release\nCIReleaseMode-Target-Name = chsrc-ci-release\n\nCFLAGS_debug  = -g -DXY_DEBUG\nCFLAGS_static = -static\nCFLAGS_optimization = -O2\n\nifdef DEBUG\n\tCFLAGS += $(CFLAGS_debug)\nendif\n\nSTATIC = 0\n\nifeq ($(STATIC), 1)\n\tCFLAGS += $(CFLAGS_static)\nendif\n#=====================================\n\n\n\n#====== CI release mode 的配置 =======\nifeq ($(MAKECMDGOALS), build-in-ci-release-mode)\n\n\tCFLAGS += $(CFLAGS_optimization)\n\n  # 仅在 Linux 上使用静态链接\n\tifeq ($(On-Linux), 1)\n\t\tCFLAGS += $(CFLAGS_static)\n\tendif\n\n  # GitHub Actions 上的 macOS 中的 LLVM 太老了\n  # 而且 gcc 被重命名为了 clang\n  # 需要直接指定版本\n  ifeq ($(On-macOS), 1)\n    CC = gcc-14\n  endif\n\nendif\n#=====================================\n\n\n\n#============ Aliases ================\nall: build\n\nb: build-in-dev-mode\nbuild: build-in-dev-mode\nbd: build-in-debug-mode\nbr: build-in-release-mode\nbcir: build-in-ci-release-mode\nd: debug\nt: test\ncheck: test\nc: clean\n#=====================================\n\n\n\nbuild-in-dev-mode:\n\t@echo Starting: Build in DEV mode: \\'$(CC)\\' $(CFLAGS) -o $(DevMode-Target-Name)\n\t@$(CC) src/chsrc-main.c $(CFLAGS) $(_C_Warning_Flags) -o $(DevMode-Target-Name)\n\t@echo Finished: Build in DEV mode\n\nbuild-in-debug-mode: CFLAGS += $(CFLAGS_debug)\nbuild-in-debug-mode:\n\t@echo Starting: Build in DEBUG mode: \\'$(CC)\\' $(CFLAGS) -o $(DebugMode-Target-Name)\n\t@$(CC) src/chsrc-main.c $(CFLAGS) $(_C_Warning_Flags) -o $(DebugMode-Target-Name)\n\t@echo Finished: Build in DEBUG mode\n\nbuild-in-release-mode: CFLAGS += $(CFLAGS_optimization)\nbuild-in-release-mode:\n\t@echo Starting: Build in RELEASE mode: \\'$(CC)\\' $(CFLAGS) -o $(ReleaseMode-Target-Name)\n\t@$(CC) src/chsrc-main.c $(CFLAGS) $(_C_Warning_Flags) -o $(ReleaseMode-Target-Name)\n\t@echo Finished: Build in RELEASE mode\n\n# CI release mode 的配置在该文件上方\nbuild-in-ci-release-mode:\n\t@echo Starting: Build in CI-RELEASE mode: \\'$(CC)\\' $(CFLAGS) -o $(CIReleaseMode-Target-Name)\n\t@$(CC) src/chsrc-main.c $(CFLAGS) $(_C_Warning_Flags) -o $(CIReleaseMode-Target-Name)\n\t@echo Finished: Build in CI-RELEASE mode\n\n# 永远重新编译\ndebug: build-in-debug-mode\n\t@$(DEBUGGER) $(DebugMode-Target-Name)\n\ntest: test-make-env test-xy test-fw\n\ntest-make-env:\n\t@echo \"On-Linux: $(On-Linux)\"\n\t@echo \"On-Windows: $(On-Windows)\"\n\t@echo \"On-macOS: $(On-macOS)\"\n\t@echo \"CC: $(CC)\"\n\t@echo \"CFLAGS: $(CFLAGS)\"\n\t@echo \"USER: $$(whoami)\"\n\t@echo \"PWD: $(shell pwd)\"\n\t@echo \"UID: $$(id -u)\"\n\t@echo \"GID: $$(id -g)\"\n# 检查HOME环境变量\n\t@if [ -z \"$(HOME)\" ]; then \\\n\t echo \"HOME environment variable is not set!\"; \\\n\telse \\\n\t echo \"HOME: $(HOME)\"; \\\n\tfi\n\n# 这两个测试文件都用 DEBUG mode\ntest-xy: CFLAGS += $(CFLAGS_debug)\ntest-xy:\n\t@$(CC) test/xy.c $(CFLAGS) -o xy\n\t@./xy\n\ntest-fw: CFLAGS += $(CFLAGS_debug)\ntest-fw:\n\t@$(CC) test/fw.c $(CFLAGS) -o fw\n\t@./fw\n\ncheck: test\n\n# AUR package 安装时将执行此 target\nfastcheck: $(DevMode-Target-Name)\n\t@perl ./test/cli.pl fastcheck\n\ntest-cli: $(DevMode-Target-Name)\n\t@perl ./test/cli.pl\n\nclean:\n\t-@rm *.exe  2>/dev/null\n\t-@rm *.res  2>/dev/null\n\t-@rm xy     2>/dev/null\n\t-@rm fw     2>/dev/null\n\t-@rm README.md.bak*    2>/dev/null\n\n\t-@rm chsrc  \t\t\t\t\t 2>/dev/null\n\t-@rm chsrc-debug       2>/dev/null\n\t-@rm chsrc-release  \t 2>/dev/null\n\t-@rm chsrc-ci-release  2>/dev/null\n\n# -include pkg/deb/Makefile # 不这么做，因为 pkg/deb/Makefile 需要在 pkg/deb 目录下执行\n# 保持动词在前的任务名风格\nbuild-deb:\n\t@$(MAKE) -C pkg/deb deb-build\n\nclean-deb:\n\t@$(MAKE) -C pkg/deb deb-clean\n\ninstall: $(ReleaseMode-Target-Name)\n\tinstall -D -m 755 $(ReleaseMode-Target-Name) $(DESTDIR)/usr/bin/chsrc\n\tinstall -D -m 644 doc/chsrc.1 $(DESTDIR)/usr/share/man/man1/chsrc.1\n\n# 这样还是太麻烦，不用，我们还是靠 just 来调用吧\n#\n# 通过 make rawstr4c ARGS=\"[--debug] Markdown.md\" 来调用\n#rawstr4c:\n#\t@bash ./tool/rawstr4c/run/run.sh $(ARGS)\n\n.PHONY: all b build bd br bcir d t check c \\\n\tbuild-in-dev-mode build-in-debug-mode build-in-release-mode build-in-ci-release-mode \\\n\tdebug test test-make-env test-xy test-fw fastcheck test-cli clean install build-deb clean-deb rawstr4c\n"
  },
  {
    "path": "README.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : README.md\n ! Doc Authors   : 曾奥然 <ccmywish@qq.com>\n ! Contributors  : Mikachu2333 <mikachu.23333@zohomail.com>\n !               | BingChunMoLi <bingchunmoli@bingchunmoli.com>\n !               |\n ! Created On    : <2023-12-28>\n ! Last Modified : <2026-02-24>\n ! ---------------------------------------------------------- -->\n\n<div align=\"center\">\n  <img alt=\"chsrc logo\" src=\"doc/image/chsrc.png\"/>\n</div>\n\n全平台通用换源工具与框架 `chsrc`，**目标支持 Linux, Windows (native, MSYS2, Cygwin), macOS, BSD, Android 等尽可能多的操作系统环境，龙芯、飞腾、RISC-V 等尽可能多的 CPU**。\n\n我们使用 **C11** 来完成上述目标。我们并不使用 Python 或 JavaScript 等解释语言，因为一个简单的换源工具，不应该强行塞给用户一个庞大的解释器和数十、数百 MB 其他文件。\n\n本软件为**自由软件**，SDPX 软件许可证为 `GPL-3.0-or-later and MIT`\n\n<br>\n\n\n\n<table align=\"center\">\n  <tr>\n  <td>\n    <a href=\"https://trendshift.io/repositories/10744\" target=\"_blank\"><img src=\"https://trendshift.io/api/badge/repositories/10744\" alt=\"RubyMetric%2Fchsrc | Trendshift\" style=\"width: 250px; height: 55px;\" width=\"250\" height=\"55\"/></a>\n  </td>\n  <td>\n    <a href=\"https://hellogithub.com/repository/7666ba91e01e4a59be5809b02d9e8ff6\" target=\"_blank\"><img src=\"https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=7666ba91e01e4a59be5809b02d9e8ff6&claim_uid=H6YVMUy7ulev8R4&theme=dark\" alt=\"Featured｜HelloGitHub\" style=\"width: 250px; height: 54px;\" width=\"250\" height=\"54\" /></a>\n  </td>\n  </tr>\n</table>\n\n<br>\n\n\n\n## ❤️ 致所有的朋友们\n\n2025年8月11日，我因通宵重构本项目代码而被送去抢救（[#252](https://github.com/RubyMetric/chsrc/issues/252)，[突发！换源工具 chsrc 作者在重构过程中被送去 120 抢救](https://v2ex.com/t/1151802)）。大家给予的关心和帮助让我非常非常感动！在此，我衷心感谢每一位朋友！**无论是开源还是闭源，无论是否为职业程序员，我们其实都是一群使用软件、热心互助、充满友爱的人，这是一个温暖的大家庭**。\n\n我为 `chsrc` 采用 GPL 协议，怀着殷切的期望：**希望能够营造像 Richard Stallman 在创建 GNU 项目之前，在 MIT 那样的氛围——写自己用得上的软件，与大家一起开发、维护，简单纯粹，无关商业利益。就像小区、校园自发组建的足球篮球队，从一次偶然的加入，逐渐成长为互相支持的伙伴**。\n\n这次经历让我更加深刻地体会到：开源，是一种把大家联系在一起的方式，**它让友情、互助和协作成为可能，也让我们在共同的目标中建立起长期的纽带**。\n\n最后，希望大家能够**时刻关注**自己的身体，**你可以随时 `chsrc` `chown` `chgrp` `chmod` 无限次，但是无法 `chbody`**！\n\n<br>\n\n\n\n## 🤝 协作与贡献\n\n> [!TIP]\n> **`chsrc` 不仅是一个命令行工具，同时也是一个体现了 Ruby on Rails 思想的 MVC 换源框架，它甚至使你能够在不了解C语言的情况下编写出新的换源方法 (recipe)。** 配合使用 [rawstr4c], 这将比写 shell 脚本更加轻松。 [如何编写 recipe?](./doc/10-如何编写recipe.md)\n\n---\n\n> [!NOTE]\n> 这也许是你可以参与的第一个现实世界中有用的C语言项目，[用 VS Code 一分钟内上手编译、运行、测试 chsrc](./doc/01-开发与构建.md)\n>\n> 欢迎对 GitHub、Gitee 协作不熟悉的人以此为契机学习参与贡献, 欢迎任何编程初学者。[从开发到提交PR，我们覆盖全流程文档](./doc/)\n---\n\n> [!IMPORTANT]\n> **`chsrc` 可换源 65+ 目标。每个人仅仅贡献和维护自己熟悉的部分，回报是得到其他所有领域专家的帮助。** [欢迎成为 recipe 维护者](https://github.com/RubyMetric/chsrc/issues/275)\n\n<br>\n\n可参与的任务与挑战：\n\n1. [Shell auto-completion 终端命令自动补全](https://github.com/RubyMetric/chsrc/issues/204)\n\n2. [搜集默认源地址，帮助使用 `reset` 功能](https://github.com/RubyMetric/chsrc/issues/111)\n\n3. [搜集测速地址，进行精准测速](https://github.com/RubyMetric/chsrc/issues/205)\n\n4. [chsrc-bootstrap: 为不存在预编译 `chsrc` 的平台提供支持](https://github.com/RubyMetric/chsrc/issues/230)\n\n<br>\n\n<details>\n<summary>已由贡献者完成的挑战</summary>\n\n1. [[Challenge] 编写统一安装的 shell 和 PowerShell 脚本](https://github.com/RubyMetric/chsrc/issues/98)\n\n    已由 [@Efterklang] 与 [@wickdynex] 完成\n\n</details>\n\n<details>\n<summary>镜像站可用性</summary>\n\n1. <https://github.com/RubyMetric/chsrc/wiki>\n2. <https://github.com/RubyMetric/chsrc/discussions>\n\n</details>\n\n<details>\n<summary>打包</summary>\n\n想通过 `dnf`, `flatpak`, `snap` 等系统包管理工具来安装和更新`chsrc`？若可提供维护，请访问 [issue#16 on GitHub](https://github.com/RubyMetric/chsrc/issues/16)\n\n- [x] `Homebrew`\n- [x] `Scoop`\n- [x] `WinGet`\n- [x] `AUR`\n- [ ] `Flatpak`\n- [ ] `snap`\n- [ ] 缺乏其他平台/包维护者\n\n</details>\n\n<br>\n\n\n\n## 📌 示例\n\n桌面端:\n\n<div align=\"center\">\n  <img alt=\"chsrc set node\" src=\"doc/image/example-set-nodejs.png\"/>\n</div>\n\n<br>\n\n安卓:\n\n<div align=\"center\">\n  <img alt=\"chsrc set python and chsrc set termux\" src=\"doc/image/chsrc-on-Android-set-python-and-termux.jpg\" width=\"300\" height=\"750\"/>\n</div>\n\n<br>\n\n\n\n## 🚀 安装\n\n<a href=\"https://repology.org/project/chsrc/versions\">\n  <img src=\"https://repology.org/badge/vertical-allrepos/chsrc.svg\" alt=\"Packaging status\" align=\"right\">\n</a>\n\n> [!IMPORTANT]\n> 若通过下述手动方式安装，则会下载到当前目录，可直接通过 `./chsrc` 运行\n\n<details>\n<summary>Windows</summary>\n\n- 可通过 `scoop` 安装，感谢 [@Gn3po4g] 与 [@niheaven]\n\n```bash\nscoop install chsrc\n```\n\n<br>\n\n- 可通过 `WinGet` 安装，感谢 [@YU-7]\n\n```bash\nwinget install RubyMetric.chsrc\n```\n\n<br>\n\n- 可通过 `PowerShell` 脚本一键下载最新版二进制文件，感谢 [@wickdynex]\n\n    若下方链接无法访问，可使用 `https://gitee.com/RubyMetric/chsrc/raw/main/tool/installer.ps1` 替代\n\n```PowerShell\n# 使用 -Version 指定版本 (不指定时默认为 pre)\n#   1. 安装 pre 版本; 这比从包管理器安装的总是更新一些\n#   2. 安装旧版本; 有时新版本可能引入某些 Bug，临时使用旧版本解决燃眉之急\n\"& { $(iwr -useb https://chsrc.run/windows) } -Version pre\" | iex\n```\n\n<br>\n\n- 或手动下载二进制文件，这是最新版，往往比 `scoop` 提供的更新，适用于修复 Bug、添加新功能后及时使用，以及未安装 `scoop` 时\n\n```bash\n# x64\ncurl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x64-windows.exe -o chsrc.exe\n\n# x86\ncurl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x86-windows.exe -o chsrc.exe\n```\n\n</details>\n\n\n\n<details>\n<summary>Linux</summary>\n\n- 可通过 `apt`/`dpkg` 安装，感谢 [@sanchuanhehe]\n\n```bash\n# x64\n$ curl -LO https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc_latest-1_amd64.deb\n\n# 也可以使用 Wget\nwget https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc_latest-1_amd64.deb\n\n$ sudo apt install ./chsrc_latest-1_amd64.deb\n# 或\n$ sudo sudo dpkg -i chsrc_latest-1_amd64.deb\n```\n\n<br>\n\n- 支持 `AUR`，可通过 `yay` 安装，感谢 [@Jerry-Terrasse]\n\n```bash\n# AUR\n$ yay -S chsrc-bin # Binary from GitHub Release\n$ yay -S chsrc-git # Build  from the latest main branch (stable)\n$ yay -S chsrc     # Build  from GitHub Release\n```\n\n<br>\n\n- 可通过 `shell` 脚本一键安装最新版，感谢 [@Efterklang] 与 [@wickdynex]\n\n    若下方链接无法访问，可使用 `https://gitee.com/RubyMetric/chsrc/raw/main/tool/installer.sh` 替代\n\n```bash\n# 非root用户默认安装至 ~/.local/bin\n$ curl https://chsrc.run/posix | bash\n\n# 也可以使用 Wget\n$ wget -O - https://chsrc.run/posix | bash\n\n# root用户默认安装至 /usr/local/bin\n$ curl https://chsrc.run/posix | sudo bash\n\n# 使用 -d 指定目录安装\n$ curl https://chsrc.run/posix | bash -s -- -d ./\n\n# 使用 -v 指定版本 (不指定时默认为 pre)\n#   1. 安装 pre 版本; 这比从包管理器安装的总是更新一些\n#   2. 安装旧版本; 有时新版本可能引入某些 Bug，临时使用旧版本解决燃眉之急\n$ curl https://chsrc.run/posix | bash -s -- -v 0.2.1\n\n# 使用 -l en 输出英文\n$ curl https://chsrc.run/posix | bash -s -- -l en\n```\n\n<br>\n\n- 可手动下载二进制文件安装\n\n```bash\n# x64\ncurl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x64-linux -o chsrc; chmod +x ./chsrc\n\n# aarch64\ncurl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-aarch64-linux -o chsrc; chmod +x ./chsrc\n\n# riscv64\ncurl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-riscv64-linux -o chsrc; chmod +x ./chsrc\n\n# armv7\ncurl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-armv7-linux -o chsrc; chmod +x ./chsrc\n```\n\n如果你所在的处理器架构没有预编译版本，可以使用 [chsrc-bootstrap]\n\n</details>\n\n\n\n<details>\n<summary>macOS</summary>\n\n- 可通过 `homebrew` 安装，感谢 [@Aaron-212] 与 [@chenrui333]\n\n```bash\nbrew install chsrc\n```\n\n<br>\n\n- 可通过 `shell` 脚本安装最新版，感谢 [@Efterklang] 与 [@wickdynex]\n\n    若下方链接无法访问，可使用 `https://gitee.com/RubyMetric/chsrc/raw/main/tool/installer.sh` 替代\n\n```bash\n# 非root用户默认安装至 ~/.local/bin\n$ curl https://chsrc.run/posix | bash\n\n# root用户默认安装至 /usr/local/bin\n$ curl https://chsrc.run/posix | sudo bash\n\n# 使用 -d 指定目录安装\n$ curl https://chsrc.run/posix | bash -s -- -d ./\n\n# 使用 -v 指定版本 (不指定时默认为 pre)\n#   1. 安装 pre 版本; 这比从包管理器安装的总是更新一些\n#   2. 安装旧版本; 有时新版本可能引入某些 Bug，临时使用旧版本解决燃眉之急\n$ curl https://chsrc.run/posix | bash -s -- -v 0.2.1\n\n# 使用 -l en 输出英文\n$ curl https://chsrc.run/posix | bash -s -- -l en\n```\n\n<br>\n\n- 或手动下载二进制文件，这是最新版，往往比 `homebrew` 提供的更新，适用于修复 Bug、添加新功能后及时使用\n\n```bash\n# arm64/aarch64\ncurl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-aarch64-macos -o chsrc; chmod +x ./chsrc\n\n# x64\ncurl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x64-macos -o chsrc; chmod +x ./chsrc\n```\n\n</details>\n\n\n\n<details>\n<summary>BSD</summary>\n\n如果已安装好了编译 `chsrc` 所需要的依赖，可直接运行:\n\n```bash\ngit clone https://gitee.com/RubyMetric/chsrc.git; cd chsrc\nclang -Iinclude -Ilib src/chsrc-main.c -o chsrc\n```\n\n**如果还不存在这些依赖，你将会被死锁住: 我还没有换源，我该如何安装这些依赖呢？**\n\n这就是 [chsrc-bootstrap] 起作用的时刻，你可使用BSD系统的原生脚本语言编写 `bootstrapper`，[并向我们提交](https://github.com/RubyMetric/chsrc/issues/230)\n\n注: `chsrc` 实现的 `FreeBSD recipe` 长期存在问题，因此一个新的 `bootstrapper` 是相当必要的，请帮助你自己和大家!\n\n</details>\n\n\n\n<details>\n<summary>Android/Termux</summary>\n\nTermux 中默认无 `Wget`，我们都用 `cURL` 来下载安装\n\n```bash\n# arm64/aarch64\ncurl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-arm64-android -o chsrc; chmod +x ./chsrc\n```\n\n如果你所在的处理器架构没有预编译版本，可以使用 [chsrc-bootstrap]:\n\n```bash\ncurl -L https://gitee.com/RubyMetric/chsrc/raw/main/bootstrap/Termux.bash | bash\n```\n\n</details>\n\n\n\n<details>\n<summary>其他平台</summary>\n\n若你所在的平台不存在预编译好的 `chsrc`，你需要手动编译。如果已安装好了编译 `chsrc` 所需要的依赖，可直接运行:\n\n```bash\ngit clone https://gitee.com/RubyMetric/chsrc.git; cd chsrc; make\n```\n\n**如果还不存在这些依赖，你将会被死锁住: 我还没有换源，我该如何安装这些依赖呢？**\n\n这就是 [chsrc-bootstrap] 起作用的时刻，你可使用该平台原生脚本语言编写 `bootstrapper`，[并向我们提交](https://github.com/RubyMetric/chsrc/issues/230)\n\n</details>\n\n<br>\n\n## 💡 使用\n\n```bash\n名称:\n   chsrc - Change Source - (GPLv3+)\n\n使用:\n   chsrc <command> [options] [target] [mirror]\n\n命令:\n   help,  h                   打印此帮助，或 -h, --help\n   issue, i                   查看相关issue\n\n   list, ls, l                列出可用镜像站和可换源目标\n   list  mirror|target        列出支持的: 镜像站/换源目标\n   list  os|lang|ware         列出支持的: 操作系统/编程语言/软件\n   list   <target>            查看该目标可用源与支持功能\n\n   measure, m, cesu <target>  对该目标所有源测速\n\n   get, g <target>            查看该目标当前源的使用情况\n\n   set, s <target>            换源，自动测速后挑选最快源\n   set    <target>  first     换源，使用维护团队测速第一的源\n   set    <target> <mirror>   换源，指定使用某镜像站 (通过list <target>查看)\n   set    <target>  <URL>     换源，用户自定义源URL\n   reset  <target>            重置，使用上游默认使用的源\n\n选项:\n   -dry                       Dry Run，模拟换源过程，命令仅打印并不运行\n   -scope=project|user|system 仅对本项目换源 / 用户级换源 / 系统级换源 (通过ls <target>查看)\n   -ipv6                      使用IPv6测速\n   -en(glish)                 使用英文输出\n   -no-color                  无颜色输出\n```\n\n<br>\n\n```bash\n自动测速，寻找最快者，换源\n\n    $ chsrc set ruby\n\n不想自动测速的时候，可使用维护团队测试的最快镜像站\n\n    $ chsrc set ruby first\n\n先列出可用的镜像站，然后选择其一，如使用 RubyChina 作为镜像站\n\n    $ chsrc ls  ruby\n    $ chsrc set ruby rubychina\n\n若有自己的镜像，可以使用自定义URL\n\n    $ chsrc set ruby https://gems.ruby-china.com/\n\n对支持 *项目级* 换源的目标，可以避免全局（*系统级* 或 *用户级*）换源\n\n    $ chsrc set -scope=project bundler\n    $ chsrc set -scope project pdm\n```\n\n<br>\n\n## 编程语言开发\n\n```bash\nchsrc set ruby|rb|gem|bundler|rubygems\n\nchsrc set python | py | pypi # 同时换 pip, poetry, pdm, uv 这4个包管理器，也可以4个独立换源\n  chsrc set pip\n  chsrc set poetry\n  chsrc set pdm\n  chsrc set uv\n\nchsrc set rye\n\nchsrc set node | nodejs # 同时换 npm, yarn 和 pnpm 这3个包管理器，也可以3个独立换源\n  chsrc set npm\n  chsrc set yarn\n  chsrc set pnpm\n\nchsrc set nvm\nchsrc set bun\n\nchsrc set perl | cpan\nchsrc set php  | composer\nchsrc set lua  | luarocks\n\nchsrc set rust | cargo | crate\nchsrc set rustup\n\nchsrc set go\nchsrc set java    | maven | mvn | maven-daemon | mvnd | gradle\nchsrc set clojure | clojars\nchsrc set dart    | pub\nchsrc set flutter\nchsrc set haskell | hackage | cabal | stack\nchsrc set ocaml   | opam\n\n# 同时会为 bioconductor 换源\nchsrc set r | cran\nchsrc set julia\n```\n\n<br>\n\n## 操作系统\n\n```bash\nsudo chsrc set ubuntu\nsudo chsrc set zorinos\nsudo chsrc set linuxmint\nsudo chsrc set debian\nsudo chsrc set fedora\n# 同时支持 Leap 和 Tumbleweed\nsudo chsrc set opensuse\nsudo chsrc set kali\nsudo chsrc set arch\nsudo chsrc set archlinuxcn\nsudo chsrc set manjaro\nsudo chsrc set gentoo\nsudo chsrc set rocky | rockylinux\nsudo chsrc set alma  | almalinux\nsudo chsrc set alpine\nsudo chsrc set voidlinux\nsudo chsrc set solus\nsudo chsrc set ros   | ros2\nsudo chsrc set trisquel\nsudo chsrc set linuxlite\nsudo chsrc set raspi | raspberrypi\nsudo chsrc set armbian\nsudo chsrc set openwrt\n\nsudo chsrc set openeuler\nsudo chsrc set openanolis | anolis\nsudo chsrc set openkylin\nsudo chsrc set deepin\n\nchsrc set msys2 | msys\n\n# Android\nchsrc set termux\n\n# BSD\nsudo chsrc set freebsd\nsudo chsrc set openbsd\nsudo chsrc set netbsd\n```\n\n<br>\n\n## 软件\n\n```bash\nchsrc set winget\nchsrc set brew      | homebrew\nchsrc set cocoapods | cocoa | pod\nchsrc set dockerhub | docker\nchsrc set flathub   | flatpak\nchsrc set nix\nchsrc set guix\nchsrc set emacs  | elpa\nchsrc set tex    | ctan | latex | texlive | miktex\nchsrc set conda  | anaconda\n```\n\n<br>\n\n## 📝 许可证\n\n- `chsrc` 主程序采用 `GPL-3.0-or-later` 许可证，保证该软件的永久自由\n- `xy.h` 使用 `MIT` 许可证，保证该库可以在尽可能多的情况下复用\n\n<br>\n\n## ❤️ 致谢\n\n感谢各个镜像站提供的优质免费镜像服务\n\n1. [mirror.c](./src/framework/mirror.c) 包含了通用的镜像站信息\n2. 各个recipe内部定义的专用镜像站\n\n另外特别感谢以下组织或项目:\n\n1. [校园网联合镜像站(MirrorZ)](https://help.mirrors.cernet.edu.cn/)\n2. [清华大学 Tuna](https://mirrors.tuna.tsinghua.edu.cn/)\n3. [上海交通大学软件源镜像服务](https://mirrors.sjtug.sjtu.edu.cn/)\n4. [中国科学技术大学 Linux 用户协会](https://github.com/ustclug)\n5. [Thanks Mirror 项目](https://github.com/eryajf/Thanks-Mirror) by [@eryajf](https://github.com/eryajf)\n\n<br>\n\n## 🚀 赞赏支持\n\n你是否因为 `chsrc` 而受到启发、节省了时间精力 or whatever?\n\n爱发电主页: <https://afdian.com/a/ccmywish>\n\n<img src=\"https://raw.githubusercontent.com/ccmywish/support-my-oss-work/main/wechat-reward.png\" alt=\"wechat-reward\" style=\"width:300px;\"/>\n\n<br>\n\n[rawstr4c]:        https://github.com/RubyMetric/rawstr4c\n[chsrc-bootstrap]: ./bootstrap/\n\n[@Aaron-212]:      https://github.com/Aaron-212\n[@chenrui333]:     https://github.com/chenrui333\n[@niheaven]:       https://github.com/niheaven\n[@Gn3po4g]:        https://github.com/Gn3po4g\n[@Jerry-Terrasse]: https://github.com/Jerry-Terrasse\n[@Efterklang]:     https://github.com/Efterklang\n[@wickdynex]:      https://github.com/wickdynex\n[@YU-7]:           https://github.com/YU-7\n[@sanchuanhehe]:   https://github.com/sanchuanhehe\n"
  },
  {
    "path": "bootstrap/README.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : (chsrc-bootstrap Introduction.md)\n ! Doc Authors   : 曾奥然 <ccmywish@qq.com>\n ! Contributors  : Nul None <nul@none.org>\n !               |\n ! Created On    : <2025-07-12>\n ! Last Modified : <2025-07-22>\n ! ---------------------------------------------------------- -->\n\n# Bootstrap\n\n```ruby\nbegin\n  download_prebuilt_chsrc_binary_for_my_platform\nrescue NoReadyMadeBinary => e\n  bootstrap! e.my_platform\nend\n```\n\n<br>\n\n\n\n## 预编译产生的死锁问题\n\n我们支持预编译的操作系统目前只有 `Windows`, `Linux`, `macOS`，支持的架构请参考[项目 README](../README.md)\n\n某些操作系统如 BSD 家族，甚至是更小众的操作系统, 或者上述操作系统的某些架构，无法享受直接下载二进制立即使用的便利性，这导致用户需要自己编译 `chsrc`.\n\n然而用户自己编译则面临着一个问题: **需要提前安装项目依赖**\n\n1. 把代码 `git clone` 下来 或 下载 `zip` 包进行解压缩\n2. C语言编译器\n3. `GNU make` 或 `just` (这二者非强制，但是有了更好)\n\n可是如果用户还没有换源，他/她又如何获得上述这些程序呢？**这是一把死锁，导致用户最终回到手动换源的原始农耕时代。**\n\n<br>\n\n\n\n## `chsrc-bootstrap` to the Rescue\n\n`chsrc-bootstrap` 是一组使用原生脚本语言的脚本，每个脚本称为 `bootstrapper`，用来完成两件事情:\n\n1. 帮助用户进行最基本的换源，让用户能够立即开始使用该系统安装其他软件\n\n2. 用户自行决定是否需要安装 `chsrc`\n\n    - 若不需要: 流程直接结束，用户已可以完成基本日常工作\n\n    - 若需要: 帮助用户安装好所需的最少依赖，并编译安装 `chsrc`\n\n注意，最基本的换源，即不测速，由维护者暂时决定先切换到某一个具体的源，先让系统跑起来。\n\n### 支持的语言\n\n上述提到的原生脚本语言只能是这些:\n\n1. Windows: `PowerShell`, `CMD`\n\n2. Linux: `Bash`, `sh`\n\n    备选: `Perl`\n\n3. macOS: `Zsh`, `Bash`, `sh`\n\n    备选: `Ruby`, `Perl`\n\n4. BSD: `sh`\n\n    备选: 待议\n\n5. 其他平台: 一切该平台支持的脚本语言，无需额外安装\n\n<br>\n\n\n\n## `chsrc` 与 `chsrc-bootstrap`\n\n`chsrc` 需要实现 `chsrc-bootstrap` 中支持的平台。这是因为，`chsrc-bootstrap` 只换到了某一个具体的源，只是临时性的，后续用户可能还想要换到其他源，此时 `chsrc` 就可以接管。\n\n而事实上，`chsrc-bootstrap` 可以完成一些操作，使得系统已经满足一些前置条件，这样的话 `chsrc` 可以在这些前置条件存在时接着换源，从而大幅减轻 `recipe` 的实现难度。\n\n<br>\n\n\n\n## 帮助\n\n1. [FreeBSD 的换源](https://github.com/RubyMetric/chsrc/issues/11) 从项目一开始就是我们的目标之一，然而由于其:\n\n    - 换源所需的步骤太多\n    - 面临着特有的鸡蛋困境\n    - BSD 工具和 GNU 工具总是有不兼容之处\n    - 在C语言中实现困难重重\n\n    因此我们一直没有很好的办法去实现\n\n2. 任何你所在的平台，都可以添加到此\n"
  },
  {
    "path": "bootstrap/Termux.bash",
    "content": "#!/usr/bin/env bash\n# ---------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# ---------------------------------------------------------------\n# File Name     : Termux.bash\n# File Authors  : Aoran Zeng <ccmywish@qq.com>\n# Contributors  : Nul None <nul@none.org>\n# Created On    : <2025-07-12>\n# Last Modified : <2026-01-21>\n#\n# Termux:\n#\n#   Bootstrap Termux: https://github.com/RubyMetric/chsrc/issues/173\n#\n#   @consult https://help.mirrors.cernet.edu.cn/termux/\n#\n#   我们默认采用校园网联合镜像站提供的源\n# ---------------------------------------------------------------\n\nbs_echo() {\n  echo \"[chsrc-bootstrap] $*\"\n}\n\nif command -v termux-change-repo &>/dev/null; then\n  termux-change-repo\nelse\n\n  # $PREFIX 的值为:  /data/data/com.termux/files/usr\n  # 用户主目录 ~ 为: /data/data/com.termux/files/home\n\n  # 必要的\n  sed -i 's@^\\(deb.*stable main\\)$@#\\1\\ndeb https://mirrors.cernet.edu.cn/termux/apt/termux-main stable main@' $PREFIX/etc/apt/sources.list\n  apt-get update\n\n  # x11-repo\n  sed -i 's@^\\(deb.*x11 main\\)$@#\\1\\ndeb https://mirrors.cernet.edu.cn/termux/apt/termux-x11 x11 main @' $PREFIX/etc/apt/sources.list.d/x11.list\n\n  # root-repo\n  sed -i 's@^\\(deb.*root main\\)$@#\\1\\ndeb https://mirrors.cernet.edu.cn/termux/apt/termux-root root main @' $PREFIX/etc/apt/sources.list.d/root.list\nfi\n\n# 立即更新测试换源状态\napt-get update && apt-get upgrade\n\nbs_echo \"基础换源已完成\"\n\nread -p \"是否需要安装 chsrc ? (y/n): \" need_install_chsrc\n\nif [[ $need_install_chsrc == \"y\" || $need_install_chsrc == \"Y\" ]]; then\n  bs_echo \"正在安装依赖项...\"\n  apt-get install -y gcc make git\n  git clone https://gitee.com/RubyMetric/chsrc.git --depth 1\n  bs_echo \"依赖安装完成!\"\n\n  bs_echo \"正在开始编译和安装\"\n  cd chsrc\n  make build-in-release-mode\n  make install\n  bs_echo \"chsrc 安装完成!\"\nfi\n"
  },
  {
    "path": "doc/01-开发与构建.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : 01-开发与构建.md\n ! Doc Authors   : 曾奥然       <ccmywish@qq.com>\n ! Contributors  : Mikachu2333  <mikachu.23333@zohomail.com>\n !               |\n ! Created On    : <2024-12-27>\n ! Last Modified : <2025-10-11>\n ! ---------------------------------------------------------- -->\n\n# 开发 chsrc\n\n## 依赖与开发环境\n\n请安装好：\n\n  1. `GCC` 或 `Clang`\n  2. [just] 或 `make`\n  3. `curl`\n  4. [rawstr4c] (可选)\n\n**我推荐你使用 VS Code 开发，你可以在一分钟内成功编译、运行和 Debug `chsrc`**\n\n  1. `Ctrl-Shift-B` 直接构建\n  2. `F5` 直接开始 Debug\n\n<br>\n\n\n\n## 获取代码\n\n**请务必使用 dev 分支开发**\n\n```bash\ngit clone https://gitee.com/RubyMetric/chsrc.git -b dev\n```\n\n关于分支的说明，可参考 [./03-CONTRIBUTING.md](./03-CONTRIBUTING.md)\n\n<br>\n\n\n\n## 编译运行\n\n共有四种构建模式：\n\n1. **`DEV mode`**\n2. **`DEBUG mode`**\n3. **`RELEASE mode`**\n4. **`CI-RELEASE mode`**\n\n开发时只需要前两种模式；第四种模式只在 GitHub Actions 使用。\n\n**如果你使用 `just`，可以在 VS Code 中获得更好的体验，按 `Ctrl-Shift-B` 直接使用 DEV mode 构建**\n\n```bash\njust (b)      # 在Windows上默认使用 gcc 编译，在macOS上默认使用 clang 编译，在其他系统上默认使用 cc 编译\njust CC=clang # 使用 clang 编译\njust CC=gcc   # 使用 gcc   编译\n\n# 编译出 debug 版本: chsrc-debug\njust bd\n# 编译出 release 版本: chsrc-release\njust br\n```\n\n<br>\n\n`make` 用户:\n\n```bash\nmake (b)      # 在Windows上默认使用 cc 编译，在macOS上默认使用 clang 编译，在其他系统上默认使用 cc 编译\nmake CC=clang # 使用 clang 编译\nmake CC=gcc   # 使用 gcc   编译\n\n# 编译出 debug 版本: chsrc-debug\nmake bd\n# 编译出 release 版本: chsrc-release\nmake br\n```\n\n<br>\n\n\n\n## Debug\n\n**如果你使用 `just`，可以在 VS Code 中获得更好的体验，按 F5 即可立即开始 Debug**\n\n```bash\n# 重新编译出 ./chsrc-debug，并启动 GDB 调试 (在macOS上启动 LLDB 调试)\n$ just debug\n\n# 重新编译出 ./chsrc-debug，并启动 LLDB 调试\n$ just DEBUGGER=lldb debug\n```\n\n<br>\n\n`make` 用户:\n\n```bash\n# 重新编译出 ./chsrc-debug，并启动 GDB 调试 (在macOS上启动 LLDB 调试)\n$ make debug\n\n# 重新编译出 ./chsrc-debug，并启动 LLDB 调试\n$ make debug DEBUGGER=lldb\n```\n\n<br>\n\n\n\n## 测试\n\n`just` 用户只需要替换下述 `make` 为 `just`\n\n```bash\nmake test-xy  # 测试 xy.h\nmake test-fw  # 测试 framework\nmake test     # 测试上述两个\nmake test-cli # 测试命令\nmake clean\n```\n\n<br>\n\n\n\n## 提交 PR\n\n关于分支的说明以及如何提交代码，请参考 [./03-CONTRIBUTING.md](./03-CONTRIBUTING.md)\n\n<br>\n\n\n\n[rawstr4c]: https://github.com/RubyMetric/rawstr4c\n[just]: https://github.com/casey/just\n"
  },
  {
    "path": "doc/02-提交与贡献.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : 02-提交与贡献.md\n ! Doc Authors   : 曾奥然 <ccmywish@qq.com>\n ! Contributors  : Nul None <nul@none.org>\n !               |\n ! Created On    : <2024-12-13>\n ! Last Modified : <2025-08-22>\n ! ---------------------------------------------------------- -->\n\n# 贡献说明\n\n## 分支\n\n- `gh-build`：仅仅在发布版本时由 `@ccmywish` 推送，触发编译到 GitHub Releases 中\n- `main`: stable，代码一定是可以编译运行的，我们假设 end users 在其他条件都得不到二进制时，会自己编译这个分支来运行 `chsrc`\n- `dev`：开发分支，工作分支，在此分支上解决冲突\n\n<br>\n\n## 提交与审阅\n\n当你提交 PR 的时候，一定要将 PR 指定 chsrc 原仓库的 dev 分支。\n\n### 一个简单的 Bug\n\n一个简单的 Bug fix，有写权限的维护者可以直接推送到主仓库的 `dev` 分支\n\n<br>\n\n### 不太容易修复的 Bug 以及新功能\n\n这里要分两种情况考虑。（1）recipe 相关的 （2）framework 相关的\n\n（1）\n\n**如果你是 recipe Chef，则你完全负责这个 recipe，如果你拥有写权限，你可以直接推送代码到 `dev` 分支**\n\n---\n\n（2）\n\n1. 需要先搜索你修改的部分涉及到的 recipe，然后提 issue @ 所有相关的 recipe Chef 来 review\n2. 如果涉及了所有 recipe，则 @ framework Chef，而无需把所有 recipe 的 Chef 都喊过来，但是如果觉得有必要，可以 @ 任意你觉得有能力 review 和能给出建议的人来 review\n\n<br>\n\n### 最好总是 issue 或 PR\n\n对于有写权限的维护者来说，即使是能够直接推代码，最好也都先提 issue 或 PR，因为这样能够让大家知道代码发生了哪些变动。\n\n如果你觉得要和大家讨论，则 issue；如果你觉得没有讨论的必要了，则直接 PR 后自己立即合并即可。之所以多此一举，是因为这能够显式地记录代码的加入过程，其相当于一份文档方便未来的自己和他人查阅\n"
  },
  {
    "path": "doc/03-为什么拒绝使用代码格式化工具.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : 03-为什么拒绝使用代码格式化工具.md\n ! Doc Authors   :  曾奥然  <ccmywish@qq.com>\n ! Contributors  : Nul None <nul@none.org>\n ! Created On    : <2025-08-10>\n ! Last Modified : <2025-08-20>\n ! ---------------------------------------------------------- -->\n\n# chsrc 代码风格\n\nRuby 的语法优美性在编程行业中具有标杆地位。Matz（松本行弘）提出的 **代码应该为人类而写，偶尔为机器执行** 这一理念，已经成为现代编程语言设计的重要指导原则。`chsrc` 项目的第一作者深受 **Ruby** 语言哲学的影响。\n\n本项目起源于 AI 编程尚未流行的时代，所有代码全部依赖人类的耐心来维护。现在，我们的代码以及这篇文章不仅会由人类阅读，也会由 AI 阅读。我们始终坚持：**代码的可读性和维护性是项目长期发展的根本保障**。\n\n<br>\n\n\n\n## 为什么我们坚持不使用代码格式化工具\n\n代码格式化工具（code formatter）在多人协作的代码仓库中确实有其价值，**参与的人越多，统一格式的需求越迫切**。然而，`chsrc` 项目经过深思熟虑后，拒绝使用代码格式化工具。让我来说明这一决定背后的深层原因。\n\n### 被强迫使用\n\n像 `Prettier` 这样的工具表面上带来了统一性，但其代价是什么？**它是极度专制的（opiniated）**，我们必须**完全交出代码审美的自主权**。今天我们大部分人使用 `Prettier`，**并非出于真心的认同，而是因为整个前端生态圈的集体胁迫——不用就意味着被边缘化**。\n\n这种现象的本质令人深思：**少数 `Prettier` 维护者的个人偏好，竟然决定了全球数百万开发者的代码美学标准。这显然是一种技术独裁，坚决拒绝向格式化工具的霸权低头**。\n\n<br>\n\n### 一致性 ≠ 美观 ≠ 可读\n\n格式化工具只保证了表面的一致性，就像一些校服，一致不一定代表美。同样，一致不一定代表代码就是最易读易懂的。\n\n每一个有追求的程序员都应该保留**对代码美学的最后决定权，格式化工具的便利性不应该以牺牲美观性和可维护性为代价**。\n\n<br>\n\n### 满足不了我们的需求\n\nC语言的格式化工具通常选择 `clang-format`，它的配置选项十分丰富，比 `Prettier` 要理性得多。然而，即便如此，**其配置的复杂性和局限性仍然无法满足 chsrc 对代码格式的严苛要求**。如果你是一位 `clang-format` 的配置专家，我们诚挚邀请您告诉我们如何优雅地处理以下代码场景，**也许这能改变我的立场**。\n\n<br>\n\n\n\n### 挑战案例\n\n以下是我认为自动格式化工具很难完美处理的代码场景：\n\n`=` 对齐：\n\n```c\nchar *name  = va_arg (args, char*);\nchar *email = va_arg (args, char*);\n```\n\n复杂逻辑的 `=` 对齐：\n\n```c\n         bool matched = iterate_menu (chsrc_pl_menu, input, &target_tmp);\nif (!matched) matched = iterate_menu (chsrc_os_menu, input, &target_tmp);\nif (!matched) matched = iterate_menu (chsrc_wr_menu, input, &target_tmp);\n```\n\n预处理指令的层次缩进：\n\n```c\n#ifdef _WIN32\n  #define XY_Build_On_Windows 1\n  #define xy_on_windows true\n  #ifdef XY_DEBUG\n    #define xy_debug_mode 1\n  #endif\n#endif\n```\n\n...... 等等\n\n<br>\n\n\n\n## C语言代码风格\n\n- 整体上基于 `GNU style`，但我们坚持自己的美学原则，在细节上有所改进\n\n- 类型名: `PascalCase_t`，即 `UpperCamelCase_t`\n\n- 函数定义和调用时，**函数名和`()`之间始终保持一个空格**，如果是在宏中，可紧凑一些，无硬性规定\n\n- 函数和函数定义之间**一般保持2个空行**\n\n    - 若函数之间有高度关联性，**可用1个空行**\n    - 若一系列函数和一系列函数存在主题性区别，**可用3个空行**\n\n<br>\n\n\n\n## Markdown 写作风格\n\n维护者很多时候不是从渲染好的界面来看 Markdown 文件的，而是阅读 Markdown 源文件，所以 Markdown 在源文件层面也要易读。\n\n我们保持每个主题之间 **1个`<br>` + 3个空行** 的简单风格。\n\n拒绝使用 VS Code 的 `markdownlint` 插件，**因为它总是用它狭隘的标准给我们增加了巨多的黄色下划线**。\n\n<br>\n\n\n\n## 其他语言代码风格\n\n我们秉承 **入乡随俗、尊重传统** 的原则，尊重每种语言社区的既定传统。比如，`YAML` 使用2个空格，`JSON`使用4个空格，`Perl` 使用 Larry Wall 钟爱的4个空格。\n\n我们使用 `.editorconfig` 来确保这些格式的应用。\n\n<br>\n"
  },
  {
    "path": "doc/10-如何编写recipe.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : 10-如何编写recipe.md\n ! Doc Authors   : 曾奥然 <ccmywish@qq.com>\n ! Contributors  : Nul None <nul@none.org>\n !               |\n ! Created On    : <2024-08-19>\n ! Last Modified : <2026-01-21>\n ! ---------------------------------------------------------- -->\n\n# Write A Recipe Even If You Don't Know C\n\n## 介绍\n\n**`chsrc` 不仅是一个命令行工具，同时也是一个体现了 Ruby on Rails 思想的 MVC 换源框架，它甚至使你能够在不了解C语言的情况下编写出新的换源方法(recipe)。**\n\n<br>\n\n我鼓励你为新的软件添加换源支持，因为通过 `chsrc` 框架，这将比写 shell 脚本更加轻松，你的贡献也将非常有价值。理论上每一个 `recipe` 都需要有专人长时间维护 ([招募](https://github.com/RubyMetric/chsrc/issues/275))。\n\n- 本项目采用 `GPLv3+` 协议，是真正的**自由软件**，而非仅仅是开源软件\n- 代码规范灵活遵循 `GNU` 标准（若标准干扰了可维护性，则并不采纳）\n- 高度模块化，目录结构清晰易懂\n- 极小依赖，极易构建，只需要 `GCC` 或 `Clang` 即可编译 (`make` 和 `just`可简化编译，但不是必需的)\n- 易于将 `shell` 脚本转换为等价的 `recipe`\n- 已有大量 `recipe` 可提供参考，并提供了 [recipe template] 供直接使用\n- 本仓库外的子项目 [rawstr4c] 帮助你在C语言中维护复杂的字符串\n- [chsrc-bootstrap] 帮助你在没有预编译 `chsrc` 的平台上 bootstrap 自己\n\n<br>\n\n成功案例:\n\n- [Armbian](../src/recipe/os/APT/Armbian.c)\n- [uv](../src/recipe/lang/Python/uv.c)\n\n<br>\n\n## 基本概念\n\n- `target`: 所要换源的目标\n- `target group`: 一个 `target` 包含了多个子 `target`，比如 `Python group` 包含了该语言的多个包管理器\n\n- `category`: 是 `target category` 的简写，即 `target` 所属的类别，可以是 **编程语言**，**操作系统**，**软件** 三类之一\n\n    1. 在目录中，三者分别为 `lang`, `os`, `ware`\n    2. 在代码中，三者前缀分别为 `pl`, `os`, `wr`\n\n- `mirror`: 是 `mirror site` 的简写，指镜像站，如清华大学开源软件镜像站\n- `source`: 该 `target` 所能换的具体的源，由 `mirror` 提供服务，往往一个 `mirror` 会提供许多 `source`\n- `recipe`: 是为一个 `target` 定义的具体换源方法，请参考 `src` 目录中的 `recipe` 目录\n\n- `chef DSL`：是 `chef Domain Specific Language` 的简写，这是一组以 `chef_` 开头的函数，用来定义维护者信息、可用源等元信息\n\n- **换源链接**: 指镜像站所提供的某一个具体的换源使用的URL\n- **测速链接**: 用来测速的URL，与 \"换源链接\" 不同，可分为 **精准测速** 和 **模糊测速**\n\n    1. 在代码中，测速链接一般使用 `smURL` (即 `speed measure URL`) 或 `speed_measure_url` 来指代\n    2. 在代码中，换源链接一般使用 `repoURL` (即 `repository URL`) 或直接用 `url` 来指代\n\n        - 为什么不用 `regurl`，因为使用术语 `repository` 的 target 远多于使用术语 `registry` 的。\n        - 为什么莫名其妙使用了大小写混合的API? 因为 `smurl` 和 `repourl` 的可读性太差\n\n- **镜像源**: 为了方便，**偶尔**我们将直接称`mirror`和/或`source`为**镜像源**，这只是一种方便性的称呼，可以统称二者，也可以根据上下文指代二者之一\n\n<br>\n\n## 编写 `recipe` 步骤\n\n1. 确定你要编写的 `target` 的标准名称，创建 `Target-Name.c` 文件\n\n    大小写需严格按官方，若名称包含空格，需使用 `-` 代替空格\n\n2. 根据类别将上述文件放在 `recipe/` 目录的某个子目录中\n\n3. 复制 [recipe template] 的内容到上述文件中，并替换 `<...>` 占位符\n\n4. 参考现有 `recipe` 的写法\n\n    1. 看一眼就能上手的参照物是 [PHP recipe](../src/recipe/lang/PHP.c)\n    2. 最好的参照物是 [Ruby recipe](../src/recipe/lang/Ruby/Ruby.c)\n    3. 组换源参照物是 [Python group recipe](../src/recipe/lang/Python/Python.c)\n\n5. 在 [Wiki] 中记录的镜像站中寻找可用源；可以额外补充镜像站\n\n6. 使用 chef DSL 定义 `_prelude()` 函数\n\n    该函数将填充 target 所有的必要信息，包括维护信息、换源信息\n\n7. [设置/修改 \"换源链接\" 和 \"测速链接\" (how?)](./11-如何设置换源链接与测速链接.md)\n\n8. 按需实现 `_setsrc()` `_getsrc()` `_resetsrc()`， 可以使用这些函数:\n\n    1. `framework/core.c` 中以 `chsrc_` 开头的所有函数或宏\n    2. `xy.h` 中以 `xy_` 开头的所有函数或宏\n    3. `chec.c` 中以 `chef_` 开头的所有函数或宏\n    4. `helper.c` 中以 `hp_` 开头的所有函数或宏\n\n    一个简单的方法是，在 VS Code 中按快捷键 `Ctrl-T` 搜索上述三种前缀\n\n9. 在 `recipe/menu.c` 中登记此 target\n\n10. [编译、运行、测试 (how?)](./01-开发与构建.md)，若无问题可提交 Pull Request\n\n<br>\n\n## 开发准则\n\n1. 代码高度可移植\n\n2. Convention over Configuration\n\n3. [NO UFO 原则: 不要乱丢文件到$HOME等目录，尤其是使用各种隐晦的文件名](https://www.yuque.com/ccmywish/blog/no-ufo)\n\n    `chsrc` 主程序不提供配置文件，不提供数据文件，干净无污染。那么在实现 `recipe` 的时候，除了备份文件外，也不要污染用户环境。\n\n<br>\n\n[rawstr4c]: https://github.com/RubyMetric/rawstr4c\n[chsrc-bootstrap]: ../bootstrap/\n[recipe template]: ../src/recipe/recipe-template.c\n[Wiki]: https://github.com/RubyMetric/chsrc/wiki\n"
  },
  {
    "path": "doc/11-如何设置换源链接与测速链接.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : 11-如何设置换源链接与测速链接.md\n ! Doc Authors   : 曾奥然 <ccmywish@qq.com>\n ! Contributors  : Nul None <nul@none.org>\n !               |\n ! Created On    : <2025-08-11>\n ! Last Modified : <2026-01-21>\n ! ---------------------------------------------------------- -->\n\n# 新增/修改 \"换源链接\"\n\n在 `_prelude()` 函数中，在 `def_sources_begin()` 的位置的**第二列**，新增/修改你想要替换的链接。\n\n**注: 以下代码仅起解释作用，JavaScript换源的真正实现可能不同**\n\n```c\ndef_sources_begin()\n{&UpstreamProvider, \"https://registry.npmjs.org/\",                     FeedByPrelude},\n{&NpmMirror,        \"https://registry.npmmirror.com\",                  FeedByPrelude},\n{&Huawei,           \"https://mirrors.huaweicloud.com/repository/npm/\", FeedByPrelude},\n{&Tencent,          \"https://mirrors.cloud.tencent.com/npm/\",          FeedByPrelude},\n{&某新镜像站,       \"某镜像站提供的换源链接\"，                         FeedByPrelude}\ndef_sources_end()\n\n//\n\n// 调整上述某一个镜像站的所提供源的 \"换源链接\"\nchef_set_repoURL (this, &UpstreamProvider, \"新的换源链接\");\n```\n\n<br>\n\n\n# 设置/修改 \"测速链接\"\n\n在 `_prelude()` 函数中，在 `def_sources_begin()` 的位置的**第三列**，设置/修改你想要替换的链接。\n\n1. 在下面代码的第一行中，我们直接给了一个链接，**这就是精准测速链接**\n2. 在下面代码的第二行和第三行中，我们都设置了一个宏 `DelegateToMirror`，这意味着我们没有直接提供精准测速链接，而是让 `chsrc` 去测试其对应镜像站定义的测速链接\n\n    - `NpmMirror` 是专用镜像站，所以其测速链接被设置为了 `ACCURATE`，即精准测速\n    - `Huawei` 是通用镜像站，所以其测速链接被设置为了 `ROUGH `，即模糊测速\n\n3. 在下面代码的第四行中，我们设置了一个宏 `FeedByPrelude`，这意味着我们将在 `_prelude()` 函数的后续动态计算 URL\n\n**注: 以下代码仅起解释作用，JavaScript换源的真正实现可能不同**\n\n```c\ndef_sources_begin()\n{&UpstreamProvider, \"https://registry.npmjs.org/\",                     \"https://registry.npmjs.org/BigFile.tar.gz\"},\n{&NpmMirror,        \"https://registry.npmmirror.com\",                  DelegateToMirror},\n{&Huawei,           \"https://mirrors.huaweicloud.com/repository/npm/\", DelegateToMirror},\n{&Tencent,          \"https://mirrors.cloud.tencent.com/npm/\",          FeedByPrelude},\ndef_sources_end()\n\n//\n\n// 调整/设置上述某一个镜像站的所提供源的 \"精准测速链接\"\nchef_set_smURL (this, &UpstreamProvider, \"新的测速链接\");\n// 设置上述某一个镜像站的所提供源的 \"精准测速链接\" 设置为 \"换源链接\" + postfix\nchef_set_smURL_with_postfix (this, &UpstreamProvider, \"/dir/BigFile.tar.gz\");\n// 基于 \"换源链接\" 做更自定义的操作\nchef_set_smURL_with_func (this, &UpstreamProvider, func, data);\n\n// 把所有上述源中还未设置 \"精准测速链接\" 的源进行设置\nchef_set_rest_smURL_with_postfix (this, \"/dir/BigFile.tar.gz\");\nchef_set_rest_smURL_with_func (this, func, data);\n\n// 调整某一个镜像站(Provider)的 \"测速链接\"\nchef_set_provider_smURL (&Tencent, \"https://mirrors.cloud.tencent.com/npm/BigFile.tar.gz\");\n// 调整某一个镜像站(Provider)的 \"测速精度\"\nchef_set_provider_sm_accuracy (&UpstreamProvider, ROUGH);\n```\n"
  },
  {
    "path": "doc/50-协作者与维护者.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : 50-协作者与维护者.md\n ! Doc Authors   : 曾奥然 <ccmywish@qq.com>\n ! Contributors  : Nul None <nul@none.org>\n !               |\n ! Created On    : <2024-12-06>\n ! Last Modified : <2025-08-22>\n ! ---------------------------------------------------------- -->\n\n# 协作者与维护者\n\n想要达到最理想的维护状态，每一个 recipe 都需要有专人长时间维护。**我们的代码里使用了 recipe (某个菜的烹饪方法) 这个词，因而整个项目便和 \"饮食\" 有关，比如 `menu`: 汇集了所有的 target 的菜单。因此，我们的维护者和贡献者身份依然使用了这个惯例：**\n\n1. **Chef**\n\n    品控 (主厨): 对一个 recipe 完全负责，有写权限时可以直接推代码\n\n    **目前项目的发展阶段还处于 *外行实现内行* 的情况，比如 Homebrew recipe，实现者根本不是 Homebrew 的真实用户，只是根据各种文档来实现，然后等待用户反馈。所以这里当前的实现者最多只能是 Cook，无法承担 Chef 的责任**\n\n2. **Cook**\n\n    掌勺：一个 recipe 的主要作者\n\n3. **Saucier**\n\n    调味：一个 recipe 的次要贡献者 (除主要作者外的其他人)\n\n<br>\n\n**Chef 采用申请制，每个 recipe 仅有1人，请提交 PULL REQUEST 在对应的 recipe 文件中添加自己，并在 [issue #275\n](https://github.com/RubyMetric/chsrc/issues/275) 留言。**\n"
  },
  {
    "path": "doc/README.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : (Document Introduction.md)\n ! Doc Authors   : 曾奥然 <ccmywish@qq.com>\n ! Contributors  : Nul None <nul@none.org>\n !               |\n ! Created On    : <2024-12-27>\n ! Last Modified : <2025-08-22>\n ! ---------------------------------------------------------- -->\n\n# 文档说明\n\nE2E (End-to-End) 开发文档:\n\n- 开发环境准备，如何编译和测试，请参考 [01-开发与构建.md](./01-开发与构建.md)\n- 直接推送还是提交 PR，请参考 [02-提交与贡献.md](./02-提交与贡献.md)\n- 代码风格，请参考 [03-为什么拒绝使用代码格式化工具.md](./03-为什么拒绝使用代码格式化工具.md)\n\n<br>\n\n具体 recipe 相关:\n\n- 如何编写一个具体的 recipe，请参考 [10-如何编写recipe.md](./10-如何编写recipe.md)\n- 如何修改换源链接、模糊/精准测速链接，请参考 [11-如何设置换源链接与测速链接.md](./11-如何设置换源链接与测速链接.md)\n\n<br>\n\n- 关于维护者身份的说明，请参考 [50-协作者与维护者.md](./50-协作者与维护者.md)\n\n<br>\n\n用户手册：\n\n1. [chsrc.1](./chsrc.1)\n2. [chsrc.texi](./chsrc.texi)\n\n<br>\n\n## 贡献指导\n\n若有任何问题，可在 [GitHub discussions](https://github.com/RubyMetric/chsrc/discussions) 中询问和讨论\n\n<br>\n"
  },
  {
    "path": "doc/chsrc.1",
    "content": ".\\\" --------------------------------------------------------------\n.\\\" SPDX-License-Identifier: GFDL-1.3-or-later\n.\\\" --------------------------------------------------------------\n.\\\" Doc Type      : Man Page\n.\\\" Doc Authors   : 曾奥然 <ccmywish@qq.com>\n.\\\" Contributors  : Nul None <nul@none.org>\n.\\\"               |\n.\\\" Created On    : <2024-08-21>\n.\\\" Last Modified : <2026-02-24>\n.\\\" ----------------------------------------------------------------\n\n.TH  chsrc  1  \"2026-02-24\"  \"v0.2.5\"  \"RubyMetric chsrc\"\n\n.SH NAME\nchsrc - Change Source for every software on every platform from the command line\n\n.SH SYNOPSIS\n.SY chsrc\n<command> [options] [target] [mirror]\n.YS\n\n\n.SH DESCRIPTION\n.SS 基本命令\n.TP\n.B help\n打印此帮助，或 h, -h, --help\n.TP\n.B issue\n查看相关issue\n\n.TP\n\\fBlist\\fR (或 \\fBls\\fR, 或 \\fBl\\fR)\n列出可用镜像源，和可换源目标\n.TP\n.B list mirror/target\n列出可用镜像源，或可换源目标\n.B list os/lang/ware\n列出可换源的操作系统/编程语言/软件\n\n.SS 测速命令\n.TP\n.B measure/cesu \\fI<target>\\fI\n对该目标所有源测速\n\n.SS 查看配置命令\n.TP\n.B list \\fI<target>\\fR\n查看该目标可用源与支持功能\n.TP\n.B get \\fI<target>\\fR\n查看该目标当前源的使用情况\n\n.SS 换源命令\n.TP\n.B set \\fI<target>\\fR\n换源，自动测速后挑选最快源\n.TP\n.B set \\fI<target>\\fR first\n换源，使用维护团队测速第一的源\n.TP\n.B set \\fI<target>\\fR \\fI<mirror>\\fR\n换源，指定使用某镜像站 (通过list <target>查看)\n.TP\n.B set \\fI<target>\\fR \\fI<https://url>\\fR\n换源，用户自定义源URL\n.TP\n.B reset \\fI<target>\\fR\n重置，使用上游默认使用的源\n\n\n\n.SH OPTIONS\n.TP\n\\fB-dry\\fR\nDry Run，模拟换源过程，命令仅打印并不运行\n.TP\n\\fB-scope\\fR\n设置换源的作用域，可选值有：project|user|system|default (通过ls \\fI<target>\\fR查看支持情况)\n.TP\n\\fB-ipv6\\fR\n使用IPv6测速\n.TP\n\\fB-en(glish)\\fR\n使用英文输出\n.TP\n\\fB-no-color\\fR\n无颜色输出\n\n\n.SH \"EXIT STATUS\"\n.br\n.TP\n0\n正常执行，一般表示换源成功\n.TP\n1\n用户环境导致的错误，如命令缺失\n.TP\n2\nchsrc 暂未实现支持\n.TP\n3\n维护者导致的镜像站、源信息相关错误\n.TP\n4\n致命错误，由内部Bug导致\n.TP\n5\n致命未知错误，往往代表内部未知Bug\n\n\n\n.SH EXAMPLES\n.EX\n# 测速，寻找最快者，换源\n$ chsrc set ruby\n\n# 列出可用的镜像站\n# 使用 RubyChina 作为镜像站\n$ chsrc ls  ruby\n$ chsrc set ruby rubychina\n\n# 可以使用自定义URL\n$ chsrc set ruby https://gems.ruby-china.com/\n\n# 使用维护团队测试的最快镜像站\n$ chsrc set ruby first\n.EE\n\n\n.SH FILES\n.B\n遵循 No UFO（Unidentified File Objects）原则：https://www.yuque.com/ccmywish/blog/no-ufo\n.PP\n因此不会有任何文件存放在你的计算机中！\n\n\n\n.\\\" .SH SEE ALSO\n\n.SH AUTHOR\nWritten by Aoran Zeng, Heng Guo and contributors. (See chsrc.c)\n\n.SH \"REPORTING BUGS\"\nOn Gitee:  https://gitee.com/RubyMetric/chsrc/issues\n.br\nOn GitHub: https://github.com/RubyMetric/chsrc/issues\n\n.SH COPYRIGHT\nCopyright (C) 2026 Aoran Zeng, Heng Guo.\nLicense GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\n.br\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n"
  },
  {
    "path": "doc/chsrc.texi",
    "content": "@c --------------------------------------------------------------\n@c SPDX-License-Identifier: GFDL-1.3-or-later\n@c --------------------------------------------------------------\n@c Doc Type      : Texinfo\n@c Doc Authors   : 曾奥然 <ccmywish@qq.com>\n@c Contributors  : Nul None <nul@none.org>\n@c               |\n@c Created On    : <2024-08-22>\n@c Last Modified : <2026-02-24>\n@c --------------------------------------------------------------\n\n\\input texinfo\n@setfilename chsrc.info\n@settitle chsrc\n\n@set Chsrc_Version v0.2.5\n@set Doc_Publish_Date 2026-02-24\n\n@copying\n@comment 这是软件copyright，不是文档copyright，因此不放在titlepage\nCopyright @copyright{} 2023-2026 曾奥然, 郭恒\n@end copying\n\n@titlepage\n@title chsrc printed manual\n@subtitle Change Source everywhere for every software!\n@author 曾奥然\n@c @insertcopying\nFor chsrc @value{Chsrc_Version}\n@page\n@end titlepage\n\n\n@contents\n\n@node Top\n@top chsrc on-terminal manual\n\nThe tool and framework @command{chsrc} is a great helper to Change Source for every software on every platform from the command line. This texinfo documentation is published on @b{@value{Doc_Publish_Date}} for @command{chsrc} @b{@value{Chsrc_Version}}\n\n@exdent 使用: chsrc <command> [options] [target] [mirror]\n\nExit status:\n\n@display\n0 正常执行，一般表示换源成功\n1 用户环境导致的错误，如命令缺失\n2 chsrc 暂未实现支持\n3 维护者导致的镜像站、源信息相关错误\n4 致命错误，由内部Bug导致\n5 致命未知错误，往往代表内部未知Bug\n@end display\n\n@noindent\n维护:\n@itemize\n@item On Gitee:  https://gitee.com/RubyMetric/chsrc/issues\n@item On GitHub: https://github.com/RubyMetric/chsrc/issues\n@end itemize\n\n\n@menu\n* commands:: 命令\n* options:: 选项\n* examples:: 例子\n@end menu\n\n@insertcopying\n\n\n\n@node commands\n@chapter 命令\n\n@section 基本命令\n@table @samp\n@item help\n打印此帮助，或 h, -h, --help\n@item issue\n查看相关issue\n\n@item list (或 ls, 或 l)\n列出可用镜像源，和可换源目标\n\n@item list mirror/target\n列出可用镜像源，或可换源目标\n\n@item list os/lang/ware\n列出可换源的操作系统/编程语言/软件\n@end table\n\n\n@section 测速命令\n@table @samp\n@item measure <target>\n@itemx cesu   <target>\n对该目标所有源测速\n@end table\n\n@page\n@section 查看配置命令\n@table @samp\n@item list <target>\n查看该目标可用源与支持功能\n\n@item get <target>\n查看该目标当前源的使用情况\n@end table\n\n\n@section 换源命令\n@table @samp\n@item set <target>\n换源，自动测速后挑选最快源\n\n@item set <target> first\n换源，使用维护团队测速第一的源\n\n@item set <target> <mirror>\n换源，指定使用某镜像站 (通过list <target>查看)\n\n@item set <target> https://url\n换源，用户自定义源URL\n\n@item reset <target>\n重置，使用上游默认使用的源\n@end table\n\n\n\n@node options\n@chapter 选项\n@table @samp\n@item -dry\nDry Run，模拟换源过程，命令仅打印并不运行\n\n@item -ipv6\n使用IPv6测速\n\n@item -scope\n设置换源的作用域，可选值有：project|user|system|default (通过ls <target>查看支持情况)\n\n@item -en(glish)\n使用英文输出\n\n@item -no-color\n无颜色输出\n@end table\n\n\n\n@node examples\n@chapter 例子\n@example\n# 测速，寻找最快者，换源\n$ chsrc set ruby\n\n# 列出可用的镜像站\n# 使用 RubyChina 作为镜像站\n$ chsrc ls  ruby\n$ chsrc set ruby rubychina\n\n# 可以使用自定义URL\n$ chsrc set ruby https://gems.ruby-china.com/\n\n# 使用维护团队测试的最快镜像站\n$ chsrc set ruby first\n@end example\n\n@bye\n"
  },
  {
    "path": "include/.keep",
    "content": ""
  },
  {
    "path": "justfile",
    "content": "#!/usr/bin/env just --justfile\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# --------------------------------------------------------------\n# Build File    : justfile\n# File Authors  : 曾奥然      <ccmywish@qq.com>\n# Contributors  : Mikachu2333 <mikachu.23333@zohomail.com>\n#               |\n# Created On    : <2025-06-18>\n# Last Modified : <2025-10-15>\n#\n# 该文件主要用于在原生Windows上执行项目的基本任务，而不借助于\n# GNU make 以及相应的 MSYS2、Cygwin 环境\n# --------------------------------------------------------------\n# just (build)\t\t\t\t\t\t\t\t\t\t\t-> chsrc.exe\n# just bd (build-in-debug-mode)\t\t\t-> chsrc-debug.exe\n# just br (build-in-release-mode)\t\t-> chsrc-release.exe\n# just debug\n# just test\n# just clean\n#\n# just STATIC=1 br  \t静态链接 (注意只能在 br 任务中使用)\n#\n# 不支持 just DEBUG=1，请直接使用 just bd (等价于 just build-in-debug-mode)\n#\n# --------------------------------------------------------------\n# 注意，由于我们要在 GitHub Actions 上编译 x32 版的 chsrc，所以需要使用 make，\n# 而不清楚 just 在 MINGW32 中的情况，所以我们在此 justfile 中并不实现关于 CI 的功能\n# --------------------------------------------------------------\n\nset windows-shell := ['cmd', '/c']\n\nCC := if os() == 'windows' {\n\t\"gcc\"\n} else if os() == 'macos' {\n\t\"clang\"\n} else {\n\t\"cc\"\n}\n\nDEBUGGER := if os() == 'windows' {\n\t\"gdb\"\n} else if os() == 'macos' {\n\t\"lldb\"\n} else {\n\t\"gdb\"\n}\n\nCFLAGS_chk_Clang := if os() == 'windows' {\n  if CC == 'clang' {\n    '-target x86_64-pc-windows-gnu'\n  } else {''}\n} else {''}\n\n\nCFLAGS_base := '-Iinclude -Ilib ' + CFLAGS_chk_Clang\n\nWARN := '-Wall -Wextra -Wno-unused-variable -Wno-unused-function -Wno-missing-braces -Wno-misleading-indentation' + ' ' + \\\n\t'-Wno-missing-field-initializers -Wno-unused-parameter -Wno-sign-compare'\nCFLAGS_warn := WARN\n\n\nCFLAGS_debug := '-g -DXY_DEBUG'\n\nDevMode-Target-Name     := 'chsrc'\nDebugMode-Target-Name   := 'chsrc-debug'\nReleaseMode-Target-Name := 'chsrc-release'\n\nSTATIC := '0'\n\nCFLAGS_static := \"-static\"\n\nCFLAGS_chk_static := if STATIC == '1' {\n\tCFLAGS_static\n} else { \"\" }\n\n\nCFLAGS_optimization := \"-O2\"\n\n\nCFLAGS_dev_mode_prompt \t   := CFLAGS_base\nCFLAGS_debug_mode_prompt \t := CFLAGS_base + ' ' + CFLAGS_debug\nCFLAGS_release_mode_prompt := CFLAGS_base + ' ' + CFLAGS_optimization + ' ' + CFLAGS_chk_static\n\nCFLAGS_dev_mode     := CFLAGS_dev_mode_prompt     + ' ' + CFLAGS_warn\nCFLAGS_debug_mode   := CFLAGS_debug_mode_prompt   + ' ' + CFLAGS_warn\nCFLAGS_release_mode := CFLAGS_release_mode_prompt + ' ' + CFLAGS_warn\n\n#=======================\n\nBIN_xy := if os() == 'windows' {'xy.exe'} else {'./xy'}\nBIN_fw := if os() == 'windows' {'fw.exe'} else {'./fw'}\nBIN_rm := if os() == 'windows' {'del'}    else {'rm'}\n#=======================\nalias b := build-in-dev-mode\nalias bd:= build-in-debug-mode\nalias br:= build-in-release-mode\nalias build:=build-in-dev-mode\nalias d := debug\nalias t := test\nalias check := test\nalias c := clean\n\ndefault: build-in-dev-mode\n\nbuild-in-dev-mode:\n\t@echo Starting: Build in DEV mode: '{{CC}}' {{CFLAGS_dev_mode_prompt}} -o {{DevMode-Target-Name}}\n\t@{{CC}} src/chsrc-main.c {{CFLAGS_dev_mode}} -o {{DevMode-Target-Name}}\n\t@echo Finished: Build in DEV mode\n\nbuild-in-debug-mode:\n\t@echo Starting: Build in DEBUG mode: '{{CC}}' {{CFLAGS_debug_mode_prompt}} -o {{DebugMode-Target-Name}}\n\t@{{CC}} src/chsrc-main.c {{CFLAGS_debug_mode}} -o {{DebugMode-Target-Name}}\n\t@echo Finished: Build in DEBUG mode\n\nbuild-in-release-mode:\n  @echo Starting: Build in RELEASE mode: '{{CC}}' {{CFLAGS_release_mode_prompt}} -o {{ReleaseMode-Target-Name}}\n  @{{ if os() == 'windows' { \\\n        '(if exist chsrc.res del chsrc.res)' + \\\n        ' & windres src/resource/chsrc.rc -O coff -o chsrc.res' \\\n      } else { '' } }}\n  @{{ if os() == 'windows' { \\\n      CC + ' src/chsrc-main.c chsrc.res ' + CFLAGS_release_mode + ' -o ' + ReleaseMode-Target-Name \\\n    } else { \\\n      CC + ' src/chsrc-main.c '           + CFLAGS_release_mode + ' -o ' + ReleaseMode-Target-Name \\\n    } }}\n  @echo Finished: Build in RELEASE mode\n\ndebug: build-in-debug-mode\n  @{{DEBUGGER}} {{DebugMode-Target-Name}}\n\ntest: test-xy test-fw\n\n# 这两个测试文件都用 DEBUG mode\ntest-xy:\n\t@{{CC}} test/xy.c {{CFLAGS_debug_mode}} -o xy\n\t@{{BIN_xy}}\n\ntest-fw:\n\t@{{CC}} test/fw.c {{CFLAGS_debug_mode}} -o fw\n\t@{{BIN_fw}}\n\nfastcheck:\n\t@perl ./test/cli.pl fastcheck\n\ntest-cli:\n\t@perl ./test/cli.pl\n\nclean:\n\t-@{{BIN_rm}} *.exe\n\t-@{{BIN_rm}} *.res\n\t-@{{BIN_rm}} xy\n\t-@{{BIN_rm}} fw\n\t-@{{BIN_rm}} chsrc\n\t-@{{BIN_rm}} chsrc-debug\n\t-@{{BIN_rm}} chsrc-release\n\t-@{{BIN_rm}} README.md.bak*\n\n# 使用: just rawstr4c [--debug] Markdown.md\n# rawstr4c *args:\n#\t@{{ if os() == 'windows' { 'tool\\\\rawstr4c\\\\run\\\\run.bat' } else { 'bash ./tool/rawstr4c/run/run.sh' } }} {{args}}\n"
  },
  {
    "path": "lefthook.yml",
    "content": "# ---------------------------------------------------------------\n# Lefthook File : lefthook.yml\n# File Authors  : 曾奥然 <ccmywish@qq.com>\n# Contributors  : Nul None <nul@none.org>\n#               |\n# Created On    : <2025-10-28>\n# Last Modified : <2025-10-30>\n# ---------------------------------------------------------------\n\nmin_version: 2.0.1\n\npre-commit:\n  only:\n    - ref: dev\n  parallel: false\n  jobs:\n    - name: 试运行 DEBUG mode\n      # 触发所有 _prelude() 函数检查\n      run: |\n        just build-in-debug-mode\n        ./chsrc-debug get pip\n      glob: \"*.{c,h}\"\n      exclude: test/*\n\n    - name: 测试 xy.h\n      run: just test-xy\n      glob:\n        - lib/xy.h\n        - test/xy.c\n\n    - name: 测试 framework\n      run: just test-fw\n      glob:\n        - \"src/framework/*.{c,h}\"\n        - src/chsrc-main.c\n        - test/fw.c\n\npost-merge:\n  only:\n    - ref: main\n  jobs:\n    - name: 测试编译 DEV mode\n      run: just build-in-dev-mode\n\npre-push:\n  only:\n    - ref: gh-build\n  jobs:\n    - name: 测试编译 RELEASE mode\n      run: just build-in-release-mode\n\n    - name: 测试运行\n      run: just test-cli\n"
  },
  {
    "path": "lib/xy.h",
    "content": "/** ------------------------------------------------------------\n * Copyright © 2023-2026 曾奥然, 郭恒\n * SPDX-License-Identifier: MIT\n * -------------------------------------------------------------\n * Lib Authors   :  曾奥然 <ccmywish@qq.com>\n *               |   郭恒  <2085471348@qq.com>\n * Contributors  : Mikachu2333 <mikachu.23333@zohomail.com>\n *               | juzeon <skyjuzheng@gmail.com>\n *               | BingChunMoLi <bingchunmoli@bingchunmoli.com>\n *               |\n * Created On    : <2023-08-28>\n * Last Modified : <2025-12-31>\n *\n *\n *                     xy: 襄阳、咸阳\n *\n * 为跨平台命令行应用程序准备的 C11 实用函数和宏 (utilities)\n *\n * 该库的特点是混合多种编程语言风味 (绝大多数为 Ruby)，每个 API\n * 均使用 @flavor 标注其参考依据\n * ------------------------------------------------------------*/\n\n#ifndef XY_H\n#define XY_H\n\n#define _XY_Version       \"v0.2.2.0-2025/10/28\"\n#define _XY_Maintain_URL  \"https://github.com/RubyMetric/chsrc/blob/dev/lib/xy.h\"\n#define _XY_Maintain_URL2 \"https://gitee.com/RubyMetric/chsrc/blob/dev/lib/xy.h\"\n\n#if defined(__STDC__) && __STDC_VERSION__ < 201112L\n#   error \"xy.h requires C11 or later, please use a new compiler which at least supports C11\"\n#endif\n\n#if defined(__STDC__) && __STDC_VERSION__ < 201710L\n#   warning \"xy.h recommends a C17 or later compiler\"\n#endif\n\n#include <assert.h>\n#include <ctype.h>\n#include <stdarg.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <dirent.h> // opendir() closedir()\n\n#if defined(__STDC__) && __STDC_VERSION__ >= 202311\n  #define XY_Deprecate_This(msg) [[deprecated(msg)]]\n#elif defined(__GNUC__) || defined(__clang__)\n  #define XY_Deprecate_This(msg) __attribute__((deprecated(msg)))\n#elif defined(_MSC_VER)\n  #define XY_Deprecate_This(msg) __declspec(deprecated(msg))\n#else\n  #define XY_Deprecate_This(msg)\n#endif\n\n\n\n/* 全局变量 与 全局状态 */\nstruct\n{\n  bool enable_color;\n\n  bool inited;\n\n  bool on_windows;\n  bool on_linux;\n  bool on_macos;\n  bool on_bsd;\n  bool on_android;\n\n  /* @flavor 同 just 中的 os_family()，只区分 windows, unix */\n  char *os_family;\n  char *os_devnull;\n}\nxy =\n{\n  .enable_color = true,\n\n  /* 由 xy_init() 赋值 */\n\n  .inited = false,\n\n  .on_windows = false,\n  .on_linux = false,\n  .on_macos = false,\n  .on_bsd = false,\n  .on_android = false,\n\n  .os_family = NULL,\n  .os_devnull = NULL\n};\n\n\n\n#ifdef _WIN32\n  #define XY_Build_On_Windows 1\n\n  #include <windows.h>\n  #include <shlobj.h>\n\n#elif defined(__linux__) || defined(__linux)\n  #define XY_Build_On_Linux 1\n  #define XY_Build_On_Unix  1\n\n#elif defined(__APPLE__)\n  #define XY_Build_On_macOS 1\n  #define XY_Build_On_Unix  1\n\n#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)\n  #define XY_Build_On_BSD  1\n  #define XY_Build_On_Unix 1\n#endif\n\n\n\n/**\n *  assert() 会被 NDEBUG 关闭，但我们也没有必要强制开启它，还是留给用户定义\n */\n// #undef NDEBUG\n#define xy_noop() ((void)0)\n\n#define assert_str(a, b) assert (xy_streql ((a), (b)))\n\n#define xy_throw(reason) assert(!reason)\n\n/**\n * @depreacated 避免消极用语\n *\n * @flavor Perl, PHP, Raku\n */\n// #define die xy_throw\n\n/**\n * @depreacated 避免消极用语\n */\n// #define xy_panic xy_throw\n\n#define xy_unsupported()    xy_throw(\"Unsuppoted\")\n#define xy_unimplemented()  xy_throw(\"Unimplemented temporarily\")\n#define xy_unreached()      xy_throw(\"This code shouldn't be reached\")\n#define xy_cant_be_null(p)  if(!p) xy_throw(\"This pointer can't be null\")\n\n\nstatic inline void\n_xy_internal_warn (char *str)\n{\n  fprintf (stderr, \"[xy.h] %s\\n\", str);\n}\n\nstatic void _xy_print_int    (int n) {printf (\"%d\", n);}\nstatic void _xy_print_long   (long n) {printf (\"%ld\", n);}\nstatic void _xy_print_long_long (long long n) {printf (\"%lld\", n);}\nstatic void _xy_print_float  (float n) {printf (\"%f\", n);}\nstatic void _xy_print_double (double n) {printf (\"%f\", n);}\nstatic void _xy_print_bool   (bool b) {printf(\"%s\", (b) ? \"true\" : \"false\");}\nstatic void _xy_print_str    (char *str) {printf (\"%s\", str);}\nstatic void _xy_print_const_str (const char *str) {printf (\"%s\", str);}\n\nstatic void _xy_println_int    (int n) {printf (\"%d\\n\", n);}\nstatic void _xy_println_long   (long n) {printf (\"%ld\\n\", n);}\nstatic void _xy_println_long_long (long long n) {printf (\"%lld\\n\", n);}\nstatic void _xy_println_float  (float n) {printf (\"%f\\n\", n);}\nstatic void _xy_println_double (double n) {printf (\"%f\\n\", n);}\nstatic void _xy_println_bool   (bool b) {printf(\"%s\\n\", (b) ? \"true\" : \"false\");}\nstatic void _xy_println_str    (char *str) {printf (\"%s\\n\", str);}\nstatic void _xy_println_const_str (const char *str) {printf (\"%s\\n\", str);}\n\n/**\n * @flavor Ruby, Python\n */\n#define print(x) _Generic((x), \\\n  int:       _xy_print_int,  \\\n  long:      _xy_print_long, \\\n  long long: _xy_print_long_long, \\\n  float:     _xy_print_float,  \\\n  double:    _xy_print_double, \\\n  bool:      _xy_print_bool, \\\n  char *:    _xy_print_str,  \\\n  const char *:   _xy_print_const_str, \\\n  default:   xy_throw(\"Unsupported type for print()!\") \\\n)(x)\n\n/**\n * @flavor JVM family, Rust\n */\n#define println(x) _Generic((x), \\\n  int:       _xy_println_int,  \\\n  long:      _xy_println_long, \\\n  long long: _xy_println_long_long, \\\n  float:     _xy_println_float,  \\\n  double:    _xy_println_double, \\\n  bool:      _xy_println_bool, \\\n  char *:    _xy_println_str,  \\\n  const char *:   _xy_println_const_str, \\\n  default:   xy_throw(\"Unsupported type for println()/say()!\") \\\n)(x)\n/* @flavor Raku, Perl */\n#define say println\n/* @flavor PHP */\n#define echo println\n/**\n * @flavor HTML\n */\nvoid br ()                   { puts (\"\"); }\nvoid p (const char *s)       { printf (\"%s\\n\", s); }\n\n\n#define xy_c_array_len(arr) (sizeof (arr) / sizeof (arr[0]))\n\n\nstatic inline void *\nxy_malloc0 (size_t size)\n{\n  void *ptr = malloc (size);\n  memset (ptr, 0, size);\n  return ptr;\n}\n\n\n/**\n * @brief 替换指针内容并自动释放旧内存\n *\n * @param pptr    指向要被替换内存区域的指针的指针\n *                *pptr 可为 NULL\n * @param new_mem 新的内存区域\n */\nstatic inline void\nxy_ptr_replace (char **pptr, char *new_mem)\n{\n  xy_cant_be_null (pptr);\n\n  if (*pptr)\n    free (*pptr);\n\n  *pptr = new_mem;\n}\n\n\n/******************************************************\n *                      String\n ******************************************************/\n\n/**\n * @brief 将 str 中所有的 pat 字符串替换成 replace，返回一个全新的字符串\n *\n * @flavor Ruby: String#gsub\n *\n * @param str     原字符串\n * @param pat     要替换的字符串\n * @param replace 替换成的字符串\n *\n * @return 替换后的新字符串\n */\nstatic char *\nxy_str_gsub (const char *str, const char *pat, const char *replace)\n{\n  size_t replace_len = strlen (replace);\n  size_t pat_len = strlen (pat);\n\n  int unit = replace_len - pat_len;\n  if (unit <= 0)\n    unit = 0;\n\n  size_t len = strlen (str);\n\n  const char *cur = str;\n  int count = 0;\n\n  while (cur < str + len)\n    {\n      char *fnd = strstr (cur, pat);\n      if (fnd)\n        {\n          count++;\n          cur = fnd + pat_len;\n        }\n      else\n        break;\n    }\n  // puti(count); DEBUG 匹配次数\n\n  char *ret = malloc (unit * count + len + 1);\n  char *retcur = ret;\n\n  cur = str;\n  while (cur < str + len)\n    {\n      char *fnd = strstr (cur, pat);\n      if (fnd)\n        {\n          ptrdiff_t diff = fnd - cur;\n          strncpy (retcur, cur, diff);\n          cur = fnd + pat_len;\n\n          retcur += diff;\n          strcpy (retcur, replace);\n          retcur += replace_len;\n        }\n      else\n        break;\n    }\n  strcpy (retcur, cur);\n\n  return ret;\n}\n\n\n/**\n * @flavor 见 xy_strcat()\n */\nstatic char *\nxy_2strcat (const char *str1, const char *str2)\n{\n  size_t len = strlen (str1);\n  size_t size = len + strlen (str2) + 1;\n  char *ret = malloc (size);\n  strcpy (ret, str1);\n  strcpy (ret + len, str2);\n  return ret;\n}\n\n\n/**\n * @brief 将多个字符串连接成一个字符串\n *\n * @flavor C语言存在 strcat()，然而限制比较大，我们重新实现\n\n *   'concat' 这个API广泛应用于包括 Ruby、JavaScript、JVM family、C#\n *\n *   但由于 xy_str_concat() 显著长于 xy_strcat()，而这个 API 在 chsrc 中\n *   又大量使用，所以我们选择后者这个更简短的形式\n *\n * @param count 连接的字符串数量\n * @param ...   连接的字符串\n *\n * @return 拼接的新字符串\n */\nstatic char *\nxy_strcat (unsigned int count, ...)\n{\n  size_t al_fixed = 256;\n  char *ret = calloc (1, al_fixed);\n  // 已分配次数\n  int al_times = 1;\n  // 当前已分配量\n  size_t al_cur = al_fixed;\n\n  const char *str = NULL;\n  // 需要分配的量\n  size_t al_need = 0;\n  // 用于 strcpy() 到 ret 的哪个位置\n  char *cur = ret + 0;\n\n  va_list args;\n  va_start (args, count);\n\n  for (int i = 0; i < count; i++)\n    {\n      bool need_realloc = false;\n\n      str = va_arg (args, const char *);\n      al_need += strlen (str) + 1;\n      while (al_need > al_cur)\n        {\n          al_times += 1;\n          al_cur = al_times * al_fixed;\n          need_realloc = true;\n        }\n      // printf(\"al_times %d, al_need %zd, al_cur %zd\\n\", al_times, al_need,\n      // al_cur);\n      if (need_realloc)\n        {\n          ptrdiff_t diff = cur - ret;\n          ret = realloc (ret, al_cur);\n          cur = ret + diff;\n        }\n      if (NULL == ret)\n        {\n          _xy_internal_warn (\"xy_strcat(): No availble memory to allocate!\");\n          return NULL;\n        }\n      strcpy (cur, str);\n      // puts(ret);\n      cur += strlen (str);\n    }\n  va_end (args);\n\n  *cur = '\\0';\n  return ret;\n}\n\n\n/**\n * @brief 复制一个字符串，返回复制的新字符串\n *\n * @param str 要复制的字符串\n *\n * @return 复制的新字符串\n */\nstatic char *\nxy_strdup (const char *str)\n{\n  if (!str)\n    {\n      _xy_internal_warn (\"xy_strdup(): called with NULL!\");\n      return NULL;\n    }\n\n  size_t len = strlen (str);\n  char *new = xy_malloc0 (len + 1);\n  strcpy (new, str);\n  return new;\n}\n\n#define _XY_Str_Bold      1\n#define _XY_Str_Faint     2\n#define _XY_Str_Italic    3\n#define _XY_Str_Underline 4\n#define _XY_Str_Blink     5\n#define _XY_Str_Cross     9\n\n#define xy_str_to_bold(str)      _xy_str_to_terminal_style (_XY_Str_Bold, str)\n#define xy_str_to_faint(str)     _xy_str_to_terminal_style (_XY_Str_Faint, str)\n#define xy_str_to_italic(str)    _xy_str_to_terminal_style (_XY_Str_Italic, str)\n#define xy_str_to_underline(str) _xy_str_to_terminal_style (_XY_Str_Underline, str)\n#define xy_str_to_blink(str)     _xy_str_to_terminal_style (_XY_Str_Blink, str)\n#define xy_str_to_cross(str)     _xy_str_to_terminal_style (_XY_Str_Cross, str)\n\n#define _XY_Str_Red     31\n#define _XY_Str_Green   32\n#define _XY_Str_Yellow  33\n#define _XY_Str_Blue    34\n#define _XY_Str_Magenta 35\n#define _XY_Str_Cyan    36\n\n#define xy_str_to_red(str)     _xy_str_to_terminal_style (_XY_Str_Red, str)\n#define xy_str_to_green(str)   _xy_str_to_terminal_style (_XY_Str_Green, str)\n#define xy_str_to_yellow(str)  _xy_str_to_terminal_style (_XY_Str_Yellow, str)\n#define xy_str_to_blue(str)    _xy_str_to_terminal_style (_XY_Str_Blue, str)\n#define xy_str_to_magenta(str) _xy_str_to_terminal_style (_XY_Str_Magenta, str)\n#define xy_str_to_purple        xy_str_to_magenta\n#define xy_str_to_cyan(str)    _xy_str_to_terminal_style (_XY_Str_Cyan, str)\n\nstatic char *\n_xy_str_to_terminal_style (int style, const char *str)\n{\n  char *color_fmt_str = NULL;\n\n  if (!xy.enable_color)\n    {\n      color_fmt_str = \"%s\";\n      goto new_str;\n    }\n\n  switch (style)\n    {\n    case _XY_Str_Red:\n      color_fmt_str = \"\\e[31m%s\\e[0m\"; break;\n    case _XY_Str_Green:\n      color_fmt_str = \"\\e[32m%s\\e[0m\"; break;\n    case _XY_Str_Yellow:\n      color_fmt_str = \"\\e[33m%s\\e[0m\"; break;\n    case _XY_Str_Blue:\n      color_fmt_str = \"\\e[34m%s\\e[0m\"; break;\n    case _XY_Str_Magenta:\n      color_fmt_str = \"\\e[35m%s\\e[0m\"; break;\n    case _XY_Str_Cyan:\n      color_fmt_str = \"\\e[36m%s\\e[0m\"; break;\n    case _XY_Str_Bold:\n      color_fmt_str = \"\\e[1m%s\\e[0m\"; break;\n    case _XY_Str_Faint:\n      color_fmt_str = \"\\e[2m%s\\e[0m\"; break;\n    case _XY_Str_Italic:\n      color_fmt_str = \"\\e[3m%s\\e[0m\"; break;\n    case _XY_Str_Underline:\n      color_fmt_str = \"\\e[4m%s\\e[0m\"; break;\n    case _XY_Str_Blink:\n      color_fmt_str = \"\\e[5m%s\\e[0m\"; break;\n    case _XY_Str_Cross:\n      color_fmt_str = \"\\e[9m%s\\e[0m\"; break;\n    }\n\n\n  size_t len = 0;\nnew_str:\n  // -2 把中间%s减掉\n  len = strlen (color_fmt_str) - 2;\n  char *buf = malloc (strlen (str) + len + 1);\n  sprintf (buf, color_fmt_str, str);\n  return buf;\n}\n\n\nstatic bool\nxy_streql (const char *str1, const char *str2)\n{\n  if (NULL==str1 || NULL==str2)\n    {\n      return false;\n    }\n  return strcmp (str1, str2) == 0 ? true : false;\n}\n\nstatic bool\nxy_streql_ic (const char *str1, const char *str2)\n{\n  if (NULL == str1 || NULL == str2)\n    {\n      return false;\n    }\n\n  size_t len1 = strlen (str1);\n  size_t len2 = strlen (str2);\n  if (len1 != len2)\n    {\n      return false;\n    }\n\n  for (size_t i = 0; i < len1; i++)\n    {\n      if (tolower (str1[i]) != tolower (str2[i]))\n        {\n          return false;\n        }\n    }\n  return true;\n}\n\n\n/**\n * @flavor Ruby: String#end_with?\n */\nstatic bool\nxy_str_end_with (const char *str, const char *suffix)\n{\n  size_t len1 = strlen (str);\n  size_t len2 = strlen (suffix);\n\n  if (0 == len2)\n    return true; // 空字符串直接返回\n  if (len1 < len2)\n    return false;\n\n  const char *cur1 = str + len1 - 1;\n  const char *cur2 = suffix + len2 - 1;\n\n  for (int i = 0; i < len2; i++)\n    {\n      if (*cur1 != *cur2)\n        return false;\n      cur1--;\n      cur2--;\n    }\n  return true;\n}\n\n/**\n * @flavor Ruby: String#start_with?\n */\nstatic bool\nxy_str_start_with (const char *str, const char *prefix)\n{\n  if (NULL==str || NULL==prefix)\n    {\n      return false;\n    }\n\n  size_t len1 = strlen (str);\n  size_t len2 = strlen (prefix);\n\n  if (0 == len2)\n    return true; // 空字符串直接返回\n  if (len1 < len2)\n    return false;\n\n  const char *cur1 = str;\n  const char *cur2 = prefix;\n\n  for (int i = 0; i < len2; i++)\n    {\n      if (*cur1 != *cur2)\n        return false;\n      cur1++;\n      cur2++;\n    }\n  return true;\n}\n\n/**\n * @flavor Ruby: String#delete_prefix\n */\nstatic char *\nxy_str_delete_prefix (const char *str, const char *prefix)\n{\n  bool yes = xy_str_start_with (str, prefix);\n  if (!yes)\n    {\n      return xy_strdup (str);\n    }\n  else\n    {\n      size_t len = strlen (prefix);\n      return xy_strdup (str + len);\n    }\n}\n\n/**\n * @flavor Ruby: String#delete_suffix\n */\nstatic char *\nxy_str_delete_suffix (const char *str, const char *suffix)\n{\n  char *new = xy_strdup (str);\n  bool yes = xy_str_end_with (str, suffix);\n  if (!yes)\n    return new;\n\n  size_t len1 = strlen (str);\n  size_t len2 = strlen (suffix);\n  char *cur = new + len1 - len2;\n  *cur = '\\0';\n  return new;\n}\n\n/**\n * @flavor Ruby: String#strip\n */\nstatic char *\nxy_str_strip (const char *str)\n{\n  xy_cant_be_null (str);\n\n  const char *start = str;\n  while (*start && strchr (\"\\n\\r\\v\\t\\f \", *start))\n    start++;\n\n  if ('\\0' == *start)\n    return xy_strdup (\"\");\n\n  const char *end = start + strlen (start) - 1;\n  while (end >= start && strchr (\"\\n\\r\\v\\t\\f \", *end))\n    end--;\n\n  size_t len = (size_t) (end - start + 1);\n  char *ret = xy_malloc0 (len + 1);\n  memcpy (ret, start, len);\n  ret[len] = '\\0';\n  return ret;\n}\n\ntypedef struct\n{\n  bool   found;\n  size_t begin;\n  size_t end;\n}\nXyStrFindResult_t;\n\n/**\n * @brief 查找子串，返回是否命中以及子串在原串中的起止位置（0 基，end 为闭区间）\n */\nstatic XyStrFindResult_t\nxy_str_find (const char *str, const char *substr)\n{\n  XyStrFindResult_t result = { .found = false, .begin = 0, .end = 0 };\n\n  if (!str || !substr)\n    return result;\n\n  if ('\\0' == substr[0])\n    {\n      result.found = true;\n      return result;\n    }\n\n  const char *pos = strstr (str, substr);\n  if (!pos)\n    return result;\n\n  result.found = true;\n  result.begin = (size_t) (pos - str);\n  result.end = result.begin + strlen (substr) - 1;\n  return result;\n}\n\n/**\n * @brief 获取字符串下一行的内容\n *\n * @note 将忽略开头的换行，截取至下一个换行前（不含换行符）\n */\nstatic char *\nxy_str_next_nonempty_line (const char *str)\n{\n  if (!str)\n    return xy_strdup (\"\");\n\n  const char *cur = str;\n  while (*cur == '\\n')\n    cur++;\n\n  if ('\\0' == *cur)\n    return xy_strdup (\"\");\n\n  const char *newline = strchr (cur, '\\n');\n  size_t len = newline ? (size_t) (newline - cur) : strlen (cur);\n\n  char *ret = xy_malloc0 (len + 1);\n  strncpy (ret, cur, len);\n  ret[len] = '\\0';\n  return ret;\n}\n\n\n\n/**\n * @brief 读取文件内容并返回字符串，失败时返回空字符串\n *\n * @note 已处理 \\r\\n 和 \\r，返回的字符串均为 \\n 换行\n *\n * @flavor Ruby: IO::read\n */\nstatic char *\nxy_file_read (const char *path)\n{\n  FILE *fp = fopen (path, \"rb\");\n  if (!fp)\n    return xy_strdup (\"\");\n\n  if (fseek (fp, 0, SEEK_END) != 0)\n    {\n      fclose (fp);\n      return xy_strdup (\"\");\n    }\n\n  long size = ftell (fp);\n  if (size < 0)\n    {\n      fclose (fp);\n      return xy_strdup (\"\");\n    }\n  rewind (fp);\n\n  char *buf = xy_malloc0 ((size_t) size + 1);\n  if (!buf)\n    {\n      fclose (fp);\n      return xy_strdup (\"\");\n    }\n\n  size_t read_bytes = fread (buf, 1, (size_t) size, fp);\n  if (read_bytes < (size_t) size && ferror (fp))\n    {\n      fclose (fp);\n      free (buf);\n      return xy_strdup (\"\");\n    }\n\n  fclose (fp);\n  buf[read_bytes] = '\\0';\n\n  char *formatted_str = xy_str_gsub (buf, \"\\r\\n\", \"\\n\");\n  xy_ptr_replace (&formatted_str, xy_str_gsub (formatted_str, \"\\r\", \"\\n\"));\n\n  free (buf);\n\n  return formatted_str;\n}\n\n\n\n/******************************************************\n *                      Logging\n ******************************************************/\n\n#define _XY_Log_Plain   000000001\n#define _XY_Log_Success 000000001 << 1\n#define _XY_Log_Info    000000001 << 2\n#define _XY_Log_Warn    000000001 << 3\n#define _XY_Log_Error   000000001 << 4\n\n#define xy_log(prompt, str)  _xy_log (_XY_Log_Plain,   prompt, str)\n#define xy_succ(prompt,str)  _xy_log (_XY_Log_Success, prompt, str)\n#define xy_info(prompt,str)  _xy_log (_XY_Log_Info,    prompt, str)\n#define xy_warn(prompt,str)  _xy_log (_XY_Log_Warn,    prompt, str)\n#define xy_error(prompt,str) _xy_log (_XY_Log_Error,   prompt, str)\n\nstatic void\n_xy_log (int level, const char *prompt, const char *content)\n{\n  char *str = NULL;\n\n  bool to_stderr = false;\n\n  /**\n   * 'app: content'\n   */\n  if (level & _XY_Log_Plain)\n    {\n      str = xy_strcat (3, prompt,  \": \", content);\n    }\n  else if (level & _XY_Log_Success)\n    {\n      str = xy_strcat (3, prompt,  \": \", xy_str_to_green (content));\n    }\n  else if (level & _XY_Log_Info)\n    {\n      str = xy_strcat (3, prompt,  \": \", xy_str_to_blue (content));\n    }\n  else if (level & _XY_Log_Warn)\n    {\n      str = xy_strcat (3, prompt,  \": \", xy_str_to_yellow (content));\n      to_stderr = true;\n    }\n  else if (level & _XY_Log_Error)\n    {\n      str = xy_strcat (3, prompt,  \": \", xy_str_to_red (content));\n      to_stderr = true;\n    }\n  else\n    {\n      xy_unreached();\n    }\n\n  if (to_stderr)\n    {\n      fprintf (stderr, \"%s\\n\", str);\n    }\n  else\n    {\n      puts (str);\n    }\n  free (str);\n}\n\n\n/**\n * @flavor brkt 系列输出受 Python 的 pip 启发，为了输出方便，使用 xy.h 的程序应该\n *\n *  1.若想完全自定义颜色和输出位置：\n *\n *    应基于下述 xy_log_brkt_to 定义自己的输出函数\n *\n *  2.若想自定义颜色，而保持输出到stdout：\n *\n *    应基于下述 xy_log_brkt 定义\n *\n *  3.若对log无细致要求，想要快速使用log功能：\n *\n *    应基于下述 xy_<level>_brkt 定义自己的 app_<level>_brkt()，或直接使用 xy_<level>_brkt\n */\n\nstatic void\nxy_log_brkt_to (const char *prompt, const char *content, FILE *stream)\n{\n  char *str = xy_strcat (4, \"[\", prompt, \"] \", content);\n  fprintf (stream, \"%s\\n\", str);\n  free (str);\n}\n\n#define xy_log_brkt(prompt1,prompt2,content)   _xy_log_brkt(_XY_Log_Plain,  prompt1,prompt2,content)\n#define xy_succ_brkt(prompt1,prompt2,content)  _xy_log_brkt(_XY_Log_Success,prompt1,prompt2,content)\n#define xy_info_brkt(prompt1,prompt2,content)  _xy_log_brkt(_XY_Log_Info,   prompt1,prompt2,content)\n#define xy_warn_brkt(prompt1,prompt2,content)  _xy_log_brkt(_XY_Log_Warn,   prompt1,prompt2,content)\n#define xy_error_brkt(prompt1,prompt2,content) _xy_log_brkt(_XY_Log_Error,  prompt1,prompt2,content)\n\nstatic void\n_xy_log_brkt (int level, const char *prompt1, const char *prompt2, const char *content)\n{\n  char *str = NULL;\n\n  bool to_stderr = false;\n\n  if (level & _XY_Log_Plain)\n    {\n      str = xy_strcat (6, \"[\", prompt1, \" \", prompt2, \"] \", content);\n    }\n  else if (level & _XY_Log_Success)\n    {\n      /* [app 成功]  [app success] */\n      str = xy_strcat (6,\n        \"[\", xy_str_to_green (prompt1), \" \", xy_str_to_bold (xy_str_to_green (prompt2)), \"] \", xy_str_to_green (content));\n    }\n  else if (level & _XY_Log_Info)\n    {\n      /* [app 信息]  [app info]\n         [app 提示]  [app notice]\n      */\n      str = xy_strcat (6,\n        \"[\", xy_str_to_blue (prompt1), \" \", xy_str_to_bold (xy_str_to_blue (prompt2)), \"] \", xy_str_to_blue (content));\n    }\n  else if (level & _XY_Log_Warn)\n    {\n      /* [app 警告]  [app warn] */\n      str = xy_strcat (6,\n        \"[\", xy_str_to_yellow (prompt1), \" \", xy_str_to_bold (xy_str_to_yellow (prompt2)), \"] \", xy_str_to_yellow (content));\n      to_stderr = true;\n    }\n  else if (level & _XY_Log_Error)\n    {\n      /* [app 错误]  [app error] */\n      str = xy_strcat (6,\n        \"[\", xy_str_to_red (prompt1), \" \", xy_str_to_bold (xy_str_to_red (prompt2)), \"] \", xy_str_to_red (content));\n      to_stderr = true;\n    }\n  else\n    {\n      xy_unreached();\n    }\n\n  if (to_stderr)\n    {\n      fprintf (stderr, \"%s\\n\", str);\n    }\n  else\n    {\n      puts (str);\n    }\n  free (str);\n}\n\n\n\n/******************************************************\n *                      cross OS\n ******************************************************/\n\nstatic char *\nxy_quiet_cmd (const char *cmd)\n{\n  char *ret = NULL;\n\n  if (xy.on_windows)\n    ret = xy_2strcat (cmd, \" >nul 2>nul \");\n  else\n    ret = xy_2strcat (cmd, \" 1>/dev/null 2>&1 \");\n\n  return ret;\n}\n\n\n/**\n * @brief 执行 `cmd`，返回其输出到 stdout 的内容中的第 `n` 行，并对已经遍历过的行执行 `func`\n *\n * @param  cmd   要执行的命令\n * @param   n    指定命令执行输出到 stdout 内容中的某一行，0 表示最后一行，n (n>0) 表示第n行\n * @param  func  对遍历时经过的行的内容，进行函数调用，如果返回 true，则提前停止遍历\n *\n * @return\n *   1. 第 `n` 行的内容\n *   或\n *   2. `func` 调用后返回为 true 的行\n *\n * @note\n *   1. 由于目标行第 `n` 行会被返回出来，所以 `func` 并不执行目标行，只会执行遍历过的行\n *   或\n *   2. 由于 `func` 调用后返回为 true 的行会被返回出来，所以该返回出的行也被 `func` 执行过了\n */\nstatic char *\nxy_run_iter_lines (const char *cmd,  unsigned long n,  bool (*func) (const char *))\n{\n  const int size = 512;\n  char *buf = (char *) malloc (size);\n\n  FILE *stream = popen (cmd, \"r\");\n  if (stream == NULL)\n    {\n      _xy_internal_warn (\"xy_run_iter_lines(): popen() failed\");\n      return NULL;\n    }\n\n  char *ret = NULL;\n  unsigned long count = 0;\n\n  while (true)\n    {\n      if (NULL == fgets (buf, size, stream))\n        break;\n      /* 存在换行的总是会把换行符读出来，删掉 */\n      ret = xy_str_delete_suffix (buf, \"\\n\");\n      count += 1;\n      if (n == count)\n        break;\n      if (func)\n        {\n           if (func (ret))\n            break;\n        }\n    }\n\n  pclose (stream);\n  return ret;\n}\n\n/**\n * @brief 执行命令 `cmd`，返回第 `n` 行输出到 stdout 的内容\n *\n * @return 返回第 `n` 行输出到 stdout 的内容\n */\nstatic char *\nxy_run (const char *cmd, unsigned long n)\n{\n  return xy_run_iter_lines (cmd, n, NULL);\n}\n\n\n/**\n * @brief 执行命令 `cmd`，仅返回其 Exit Code，stdout 与 stderr 均不输出到终端\n *\n * @return 返回 `cmd` 的 Exit Code\n */\nint\nxy_run_get_status (char *cmd)\n{\n  char * command = xy_quiet_cmd (cmd);\n\n  int status = system (command);\n  return status;\n}\n\n\n/**\n * @brief 获得执行命令 `cmd` 输出到 stdout 的内容，而 stderr 依然输出到终端\n *\n * @param[in]  cmd    要执行的命令\n * @param[out] output 捕获的标准输出，\n *                    为NULL时表示不关心stdout输出，但依然允许stderr输出\n *\n * @return 返回命令的执行状态\n */\nstatic int\nxy_run_get_stdout (const char *cmd, char **output)\n{\n  int cap  = 8192; /* 假如1行100个字符，大约支持80行输出 */\n  char *buf = (char *) xy_malloc0 (cap);\n\n  FILE *stream = popen (cmd, \"r\");\n  if (stream == NULL)\n    {\n      _xy_internal_warn (\"xy_run_get_stdout(): popen() failed\");\n      return -1;\n    }\n\n  int size = 0;\n  size_t n;\n  while ((n = fread (buf + size, 1, cap - size, stream)) > 0) {\n    size += n;\n    if (size == cap)\n      {\n        cap *= 2;\n        char *new_buf = realloc (buf, cap);\n        buf = new_buf;\n      }\n    }\n  buf[size] = '\\0';\n\n  int status = pclose (stream);\n\n  if (output)\n    *output = buf;\n\n    return status;\n}\n\n\n\n/**\n * @brief 该函数返回所在 os family 的对应字符串\n */\nstatic const char *\nxy_os_depend_str (const char *str_for_win, const char *str_for_unix)\n{\n  if (xy.on_windows)\n    return str_for_win;\n  else\n    return str_for_unix;\n}\n\n\n/**\n * @brief 返回当前操作系统的 HOME 目录\n *\n * @note  Windows 上返回 %USERPROFILE%，Linux 等返回 $HOME\n * @warning Windows 上要警惕 Documents 等目录被移动位置的情况，避免使用本函数的 HOME 路径直接拼接 Documents，应参考 _xy_win_documents() 的实现\n */\n#define xy_os_home _xy_os_home ()\nstatic char *\n_xy_os_home ()\n{\n  char *home = NULL;\n  if (xy.on_windows)\n    home = getenv (\"USERPROFILE\");\n  else\n    home = getenv (\"HOME\");\n  return home;\n}\n\n\n/**\n * @brief 返回 Windows 上的 Documents 目录\n *\n * @note 警告，不可使用 HOME 目录直接拼接，若用户移动了 Documents，将导致错误\n * @warning 非 Windows 返回 NULL\n */\nstatic char *\n_xy_win_documents ()\n{\n#ifdef XY_Build_On_Windows\n  char documents_path[MAX_PATH];\n  HRESULT result = SHGetFolderPathA (NULL, CSIDL_MYDOCUMENTS, NULL,\n                                     SHGFP_TYPE_CURRENT, documents_path);\n\n  if (SUCCEEDED (result))\n    return xy_strdup (documents_path);\n\n  return xy_2strcat (xy_os_home, \"\\\\Documents\");\n#else\n  return NULL;\n#endif\n}\n\n#define xy_win_powershell_profile _xy_win_powershell_profile ()\n#define xy_win_powershellv5_profile _xy_win_powershellv5_profile ()\n\n/**\n * @brief 返回 Windows 上 pwsh (>=v5) 的配置文件路径\n *\n * @warning 非 Windows 返回 NULL\n */\nstatic char *\n_xy_win_powershell_profile ()\n{\n  if (xy.on_windows)\n    {\n      char *documents_dir = _xy_win_documents ();\n      char *profile_path = xy_2strcat (documents_dir, \"\\\\PowerShell\\\\Microsoft.PowerShell_profile.ps1\");\n      free (documents_dir);\n      return profile_path;\n    }\n  else\n    return NULL;\n}\n\n\n/**\n * @brief 返回 Windows 上自带的 powershell (v5) 的配置文件路径\n *\n * @warning 非 Windows 返回 NULL\n */\nstatic char *\n_xy_win_powershellv5_profile ()\n{\n  if (xy.on_windows)\n    {\n      char *documents_dir = _xy_win_documents ();\n      char *profile_path = xy_2strcat (documents_dir, \"\\\\WindowsPowerShell\\\\Microsoft.PowerShell_profile.ps1\");\n      free (documents_dir);\n      return profile_path;\n    }\n  else\n    return NULL;\n}\n\n#define xy_zshrc  \"~/.zshrc\"\n#define xy_bashrc \"~/.bashrc\"\n#define xy_fishrc \"~/.config/fish/config.fish\"\n\n/**\n * @note Windows上，`path` 不要夹带变量名，因为最终 access() 不会帮你转换\n */\nstatic bool\nxy_file_exist (const char *path)\n{\n  char *expanded_path = NULL;\n  const char *check_path = path;\n\n  if (xy_str_start_with (path, \"~\"))\n    {\n      expanded_path = xy_2strcat (xy_os_home, path + 1);\n      check_path = expanded_path;\n    }\n\n  // 0 即 F_OK\n  bool result = (0 == access (check_path, 0)) ? true : false;\n  if (expanded_path) free (expanded_path);\n  return result;\n}\n\n/**\n * @note `xy_file_exist()` 和 `xy_dir_exist()` 两个函数在所有平台默认都支持使用 '~'，\n *       但实现中都没有调用 `xy_normalize_path()`，以防万一，调用前可能需要用户手动调用它\n */\nstatic bool\nxy_dir_exist (const char *path)\n{\n  char *allocated_dir = NULL;\n  const char *dir = path;\n  if (xy.on_windows)\n    {\n      if (xy_str_start_with (path, \"~\"))\n        {\n          allocated_dir = xy_2strcat (xy_os_home, path + 1);\n          dir = allocated_dir;\n        }\n    }\n\n  if (xy.on_windows)\n    {\n#ifdef XY_Build_On_Windows\n      // 也可以用 opendir() #include <dirent.h>\n      DWORD attr = GetFileAttributesA (dir);\n\n      bool result = false;\n      if (attr == INVALID_FILE_ATTRIBUTES)\n        {\n          // Q: 我们应该报错吗？\n          result = false;\n        }\n      else if (attr & FILE_ATTRIBUTE_DIRECTORY)\n        {\n          result = true;\n        }\n      else\n        {\n          result = false;\n        }\n      if (allocated_dir) free (allocated_dir);\n      return result;\n#endif\n    }\n  else\n    {\n      char *tmp_cmd = xy_2strcat (\"test -d \", dir);\n      int status = system (tmp_cmd);\n      free (tmp_cmd);\n      bool result = (0==status);\n      if (allocated_dir) free (allocated_dir);\n      return result;\n    }\n\n  return false;\n}\n\n/**\n * @brief 规范化路径\n *\n * @details\n *   1. 删除路径左右两边多出来的空白符\n *      - 防止通过间接方式得到的路径包含了空白字符 (如 grep 出来的结果)\n *      - 防止维护者多写了空白字符\n *   2. 将 ~ 转换为绝对路径\n *   3. 在Windows上，使用标准的 \\ 作为路径分隔符\n */\nstatic char *\nxy_normalize_path (const char *path)\n{\n  char *new = xy_str_strip (path);\n\n  if (xy_str_start_with (new, \"~\"))\n    {\n      char *tmp = xy_str_delete_prefix (new, \"~\");\n      char *joined = xy_2strcat (xy_os_home, tmp);\n      free (tmp);\n      xy_ptr_replace (&new, joined);\n    }\n\n  if (xy.on_windows)\n    {\n      xy_ptr_replace (&new, xy_str_gsub (new, \"/\", \"\\\\\"));\n    }\n  return new;\n}\n\n\n/**\n * @brief 返回一个路径的父目录名\n *\n * @note\n *   - 返回的是真正的 \"目录名\" (就像文件名一样)，而不是 \"路径\"，所以一定是不含末尾斜杠的\n *   - 在Windows上，使用标准的 \\ 作为路径分隔符\n */\nstatic char *\nxy_parent_dir (const char *path)\n{\n  char *dir = xy_normalize_path (path);\n\n  /* 不管是否为Windows，全部统一使用 / 作为路径分隔符，方便后续处理 */\n  xy_ptr_replace (&dir, xy_str_gsub (dir, \"\\\\\", \"/\"));\n\n  if (xy_str_end_with (dir, \"/\"))\n    xy_ptr_replace (&dir, xy_str_delete_suffix (dir, \"/\"));\n\n  char *last = NULL;\n\n  last = strrchr (dir, '/');\n  if (!last)\n    {\n      /* 路径中没有一个 / 是很奇怪的，我们直接返回 . 作为当前目录 */\n      return \".\";\n    }\n  *last = '\\0';\n\n  /* Windows上重新使用 \\ 作为路径分隔符 */\n  if (xy.on_windows)\n    {\n      xy_ptr_replace (&dir, xy_str_gsub (dir, \"/\", \"\\\\\"));\n    }\n  return dir;\n}\n\n\n/**\n * @internal 仅由 xy_init () 调用\n */\nvoid\n_xy_detect_os ()\n{\n  /**\n   * 首先判断是否为 Windows\n   *\n   * SystemDrive 为 C:\n   */\n  char *drive = getenv (\"SystemDrive\");\n  if (drive)\n    {\n      char path[256];\n      snprintf (path, sizeof (path), \"%s\\\\Users\", drive);\n      DIR *d = opendir (path);\n      if (d)\n        {\n          xy.on_windows = true;\n          xy.os_family = \"windows\";\n          closedir (d);\n          return;\n        }\n    }\n\n  /* 判断 Linux */\n  FILE *fp = fopen (\"/proc/version\", \"r\");\n  if (fp)\n    {\n      char buf[256] = {0};\n      fread (buf, 1, sizeof (buf) - 1, fp);\n      fclose (fp);\n      if (strstr (buf, \"Linux\"))\n        {\n          xy.on_linux = true;\n          xy.os_family = \"unix\";\n          return;\n        }\n    }\n\n  /**\n   * 判断 Android\n   *\n   * @consult https://android.googlesource.com/platform/system/core/+/refs/heads/main/rootdir/init.environ.rc.in\n   */\n  char *android_env = getenv (\"ANDROID_ROOT\");\n  if (android_env)\n    {\n      if (xy_str_find (android_env, \"/system\").found)\n        {\n          xy.on_android = true;\n          xy.os_family = \"unix\";\n          return;\n        }\n    }\n\n  /* 判断 macOS */\n  DIR *d = opendir (\"/System/Applications\");\n  if (d)\n    {\n      closedir (d);\n      d = opendir (\"/Library/Apple\");\n      if (d)\n        {\n          xy.on_macos = true;\n          xy.os_family = \"unix\";\n          closedir (d);\n          return;\n        }\n    }\n\n  /* 最后判断 BSD */\n  fp = popen (\"uname -s\", \"r\");\n  if (fp)\n    {\n      char buf[256];\n      fgets (buf, sizeof (buf), fp);\n      pclose (fp);\n      if (strstr (buf, \"BSD\") != NULL)\n        {\n          xy.on_bsd = true;\n          xy.os_family = \"unix\";\n          return;\n        }\n    }\n  else\n    {\n      DIR *bsd_dir = opendir (\"/etc/rc.d\");\n      if (bsd_dir)\n        {\n          closedir (bsd_dir);\n          xy.on_bsd = true;\n          xy.os_family = \"unix\";\n          return;\n        }\n    }\n\n  if (!(xy.on_windows || xy.on_linux || xy.on_android || xy.on_macos || xy.on_bsd))\n    xy_throw (\"Unknown operating system\");\n}\n\n\nvoid\nxy_use_utf8 ()\n{\n#ifdef XY_Build_On_Windows\n  SetConsoleOutputCP (65001);\n#endif\n}\n\n\n/**\n * @note 该函数必须被首先调用，方能使用各个跨操作系统的函数\n */\nvoid\nxy_init ()\n{\n  _xy_detect_os ();\n\n  if (xy.on_windows)\n    xy.os_devnull = \"nul\";\n  else\n    xy.os_devnull = \"/dev/null\";\n\n  xy_use_utf8 ();\n\n  xy.inited = true;\n}\n\n\n/******************************************************\n *                      Container\n ******************************************************/\ntypedef struct XySeqItem_t\n{\n  struct XySeqItem_t *prev;\n  struct XySeqItem_t *next;\n\n  void *data;\n}\nXySeqItem_t;\n\ntypedef struct XySeq_t\n{\n  XySeqItem_t *first_item;\n  XySeqItem_t *last_item;\n\n  uint32_t length;\n}\nXySeq_t;\n\n\nXySeq_t*\nxy_seq_new (void)\n{\n  XySeq_t *seq = xy_malloc0 (sizeof (XySeq_t));\n  if (!seq) return NULL;\n\n  seq->first_item = NULL;\n  seq->last_item = NULL;\n  seq->length = 0;\n\n  return seq;\n}\n\n/**\n * @flavor Python: len()\n */\nuint32_t\nxy_seq_len (XySeq_t *seq)\n{\n  xy_cant_be_null (seq);\n  return seq->length;\n}\n\n/**\n * @flavor Ruby: Enumerable#first\n */\nvoid *\nxy_seq_first (XySeq_t *seq)\n{\n  xy_cant_be_null (seq);\n  return seq->first_item ? seq->first_item->data : NULL;\n}\n\n/**\n * @flavor Ruby: Enumerable#last\n */\nvoid *\nxy_seq_last (XySeq_t *seq)\n{\n  xy_cant_be_null (seq);\n  return seq->last_item ? seq->last_item->data : NULL;\n}\n\n/**\n * @flavor Ruby: Array#at\n *\n * @note 序号从1开始\n *\n * @return 如果seq中并没有第n个数据，则返回NULL\n */\nvoid *\nxy_seq_at (XySeq_t *seq, int n)\n{\n  xy_cant_be_null (seq);\n\n  if (0 == n) xy_throw (\"The index must begin from 1, not 0\");\n\n  if (1 == n) return seq->first_item ? seq->first_item->data : NULL;\n\n  XySeqItem_t *it = seq->first_item;\n  for (uint32_t i = 1; i < n && it; i++)\n    {\n      it = it->next;\n    }\n  return it ? it->data : NULL;\n}\n\n\n/**\n * @flavor Perl: push\n */\nvoid\nxy_seq_push (XySeq_t *seq, void *data)\n{\n  xy_cant_be_null (seq);\n\n  XySeqItem_t *it = xy_malloc0 (sizeof (XySeqItem_t));;\n\n  it->data = data;\n  it->prev = NULL;\n  it->next = NULL;\n\n  // 更新 item 间关系\n  XySeqItem_t *l = seq->last_item;\n  if (l)\n    {\n      it->prev = l;\n      l->next = it;\n    }\n\n  // 更新 seq 信息\n  seq->last_item = it;\n  if (0==seq->length)\n    seq->first_item = it;\n\n  seq->length++;\n}\n\n\n/**\n * @flavor Perl: pop\n */\nvoid *\nxy_seq_pop (XySeq_t *seq)\n{\n  xy_cant_be_null (seq);\n\n  if (0==seq->length) return NULL;\n\n  // 更新 item 间关系\n  XySeqItem_t *l = seq->last_item;\n  XySeqItem_t *p = l->prev;\n  // 考虑 seq 当前只有1项的情况\n  if (p) p->next = NULL;\n  l->prev = NULL;\n\n  // 更新 seq 信息\n  seq->last_item = p;\n  // 考虑 seq 当前只有1项的情况\n  if (!p) seq->first_item = NULL;\n  seq->length--;\n\n  void *data = l->data;\n  free (l);\n  return data;\n}\n\n\n/**\n * @flavor Ruby: Array#each\n */\nvoid\nxy_seq_each (XySeq_t *seq, void (*func) (void *, void *), void *user_data)\n{\n  xy_cant_be_null (seq);\n  xy_cant_be_null (func);\n\n  for (XySeqItem_t *it = seq->first_item; it; it = it->next)\n    {\n      func (it->data, user_data);\n    }\n}\n\n/**\n * @flavor Ruby: Enumerable#find\n */\nvoid *\nxy_seq_find (XySeq_t *seq, bool (*func) (void *, void *), void *user_data)\n{\n  xy_cant_be_null (seq);\n  xy_cant_be_null (func);\n\n  for (XySeqItem_t *it = seq->first_item; it; it = it->next)\n    {\n      if (func (it->data, user_data))\n        {\n          return it->data;\n        }\n    }\n  return NULL;\n}\n\n\n\n#define _XY_Map_Buckets_Count 97\n\nstruct _XyHashBucket_t\n{\n  struct _XyHashBucket_t *next;\n  char *key;\n  void *value;\n};\n\ntypedef struct XyMap_t\n{\n  struct _XyHashBucket_t **buckets;\n\n  uint32_t length;\n}\nXyMap_t;\n\n\nXyMap_t *\nxy_map_new ()\n{\n  XyMap_t *map = xy_malloc0 (sizeof (XyMap_t));\n  map->buckets = xy_malloc0 (sizeof (struct _XyHashBucket_t *) * _XY_Map_Buckets_Count);\n\n  map->length = 0;\n\n  return map;\n}\n\n\nuint32_t\nxy_map_len (XyMap_t *map)\n{\n  xy_cant_be_null (map);\n  return map->length;\n}\n\n\nunsigned long\nxy_hash (const char* str)\n{\n  unsigned long h = 5381;\n  int c;\n  while ((c = *str++))\n    h = ((h << 5) + h) + c; /* h * 33 + c */\n  return h;\n}\n\n\n/**\n * @flavor JavaScript: map.set\n */\nvoid\nxy_map_set (XyMap_t *map, const char *key, void *value)\n{\n  xy_cant_be_null (map);\n  xy_cant_be_null (key);\n\n  unsigned long hash = xy_hash (key);\n  uint32_t index = hash % _XY_Map_Buckets_Count;\n\n  // 若 key 已经存在\n  struct _XyHashBucket_t *maybe = map->buckets[index];\n  while (maybe)\n    {\n      if (xy_streql (maybe->key, key))\n        {\n          maybe->value = value;\n          return;\n        }\n      maybe = maybe->next;\n    }\n\n  // 若 key 不存在\n  struct _XyHashBucket_t *bucket = xy_malloc0 (sizeof (struct _XyHashBucket_t));\n\n  bucket->key = xy_strdup (key);\n  bucket->value = value;\n  bucket->next = map->buckets[index];\n  map->buckets[index] = bucket;\n\n  map->length++;\n}\n\n\n/**\n * @flavor JavaScript: map.get\n */\nvoid *\nxy_map_get (XyMap_t *map, const char *key)\n{\n  xy_cant_be_null (map);\n  xy_cant_be_null (key);\n\n  unsigned long hash = xy_hash (key);\n  uint32_t index = hash % _XY_Map_Buckets_Count;\n\n  struct _XyHashBucket_t *maybe = map->buckets[index];\n  while (maybe)\n    {\n      if (xy_streql (maybe->key, key))\n        {\n          return maybe->value;\n        }\n      maybe = maybe->next;\n    }\n\n  return NULL;\n}\n\n/**\n * @flavor Ruby: Hash#each\n */\nvoid\nxy_map_each (\n  XyMap_t *map,\n  void (*func) (const char *key, void *value, void *user_data),\n  void *user_data)\n{\n  xy_cant_be_null (map);\n  xy_cant_be_null (func);\n\n  for (uint32_t i = 0; i < _XY_Map_Buckets_Count; i++)\n    {\n      struct _XyHashBucket_t *bucket = map->buckets[i];\n      while (bucket)\n        {\n          func (bucket->key, bucket->value, user_data);\n          bucket = bucket->next;\n        }\n    }\n}\n\n\n#endif\n"
  },
  {
    "path": "pkg/AUR/README.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : README.md\n ! Doc Authors   : 曾奥然 <ccmywish@qq.com>\n ! Contributors  : Nil Null <nil@null.org>\n !               |\n ! Created On    : <2025-06-15>\n ! Last Modified : <2025-06-16>\n ! ---------------------------------------------------------- -->\n\n# AUR package\n\n本文档说明了 `chsrc` 项目的 AUR 包的相关情况\n\n<br>\n\n## 相关文件\n\nCI 维护者 [@Jerry-Terrasse](https://github.com/Jerry-Terrasse)\n\n- [.github/workflows/pub-AUR-chsrc-git.yml](../../.github/workflows/pub-AUR-chsrc-git.yml)\n- [.github/workflows/pub-AUR-chsrc-and-chsrc-bin.yml`](../../.github/workflows/pub-AUR-chsrc-git.yml)\n\n<br>\n\n## 分发\n\n位于 https://aur.archlinux.org/packages\n\n- [chsrc-bin](https://aur.archlinux.org/packages/chsrc-bin): 从 GitHub Releases 直接下载的二进制文件\n\n- [chsrc](https://aur.archlinux.org/packages/chsrc)：从 GitHub Releases 的代码构建\n\n- [chsrc-git](https://aur.archlinux.org/packages/chsrc-git)：从最新源码构建的版本，偶尔可能不稳定\n"
  },
  {
    "path": "pkg/README.md",
    "content": "# Packages\n\n## 分发情况\n\n- [x] `Homebrew`\n- [x] `Scoop`\n- [x] `WinGet`\n- [x] `AUR`\n- [ ] `Flatpak`\n- [ ] `snap`\n- [ ] ...\n\n<br>\n\n```bash\n$ brew install chsrc\n\n$ scoop install chsrc\n\n$ winget install RubyMetric.chsrc\n\nyay -S chsrc-bin # Binary from GitHub Release\nyay -S chsrc     # Build  from GitHub Release\nyay -S chsrc-git # Build  from the latest main branch (stable)\n```\n\n<br>\n\n- Homebrew\n\n  https://github.com/Homebrew/homebrew-core/blob/master/Formula/c/chsrc.rb\n\n- Scoop\n\n  https://github.com/ScoopInstaller/Main/blob/master/bucket/chsrc.json\n\n- WinGet\n\n  https://github.com/microsoft/winget-pkgs/tree/master/manifests/r/RubyMetric/chsrc\n\n- AUR:\n\n  - https://aur.archlinux.org/packages/chsrc-bin\n\n  - https://aur.archlinux.org/packages/chsrc\n\n  - https://aur.archlinux.org/packages/chsrc-git\n\n<br>\n\n\n## 打包情况\n\n- [x] `deb`\n\n<br>\n"
  },
  {
    "path": "pkg/deb/BUILD.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : BUILD.md\n ! Doc Authors   : sanchuanhehe <wyihe5520@gmail.com>\n ! Contributors  :  曾奥然 <ccmywish@qq.com>\n !               |\n ! Created On    : <2025-06-14>\n ! Last Modified : <2025-06-16>\n ! ---------------------------------------------------------- -->\n\n# 构建 deb package\n\n## 准备\n\n安装构建所需的依赖：\n\n```bash\nsudo apt-get update\nsudo apt-get install build-essential debhelper devscripts fakeroot\n```\n\n<br>\n\n## 构建\n\n```bash\ngit clone https://github.com/RubyMetric/chsrc.git\ncd chsrc\n\n# 进入 deb 目录\ncd pkg/deb\n\n# 执行构建命令\n./Makefile deb-make\n```\n\n### 调试构建\n\n```bash\n# 启用详细输出\nDEB_BUILD_OPTIONS=\"nocheck\" debuild -us -uc -b\n\n# 检查构建日志\nless ../chsrc_*.build\n\n# 检查包内容\ndpkg --contents ../chsrc_*.deb\n# 或\ndpkg-deb --contents ../chsrc_*.deb\n```\n\n### 交叉编译\n\n为不同架构进行构建：\n\n```bash\n# For ARM64\nCC=aarch64-linux-gnu-gcc dpkg-buildpackage -us -uc -b -aarm64\n\n# For ARMv7 (armhf)\nCC=arm-linux-gnueabihf-gcc dpkg-buildpackage -us -uc -b -aarmhf\n```\n\n<br>\n\n### 安装\n\n```bash\nsudo dpkg -i ../chsrc_*.deb\nsudo apt-get install -f  # 修复依赖问题\n```\n\n<br>\n\n### 测试安装情况\n\n```bash\n# 运行测试\nbash ./deb-installation-test.sh\n\n# 查看文档安装情况\nman chsrc\n\n# 查看 deb 包的 copyright\ncat /usr/share/doc/chsrc/copyright\n\n# 查看 deb 包 changelog\nzless /usr/share/doc/chsrc/changelog.Debian.gz\n```\n\n<br>\n\n### 清理构建产物\n\n```bash\n./Makefile deb-clean\n```\n\n<br>\n\n## 卸载\n\n```bash\nsudo apt-get remove chsrc\n```\n\n包括删除配置在内的完全删除：\n\n```bash\nsudo apt-get purge chsrc\n```\n\n<br>\n\n\n## 故障排查\n\n常见问题：\n\n1. **构建失败**: 检查 debian/control 中的依赖是否正确\n2. **交叉编译失败**: 确认目标架构的工具链已正确安装\n3. **安装测试失败**: 检查 postinst 脚本是否有错误\n\n<br>\n"
  },
  {
    "path": "pkg/deb/CI.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : CI.md\n ! Doc Authors   : sanchuanhehe <wyihe5520@gmail.com>\n ! Contributors  :  曾奥然 <ccmywish@qq.com>\n !               |\n ! Created On    : <2025-06-14>\n ! Last Modified : <2025-06-16>\n ! ---------------------------------------------------------- -->\n\n# deb package CI/CD\n\n本文档说明了 chsrc 项目的 deb 包自动构建和发布流程。\n\n## CI 文件\n\nCI 维护者 [@sanchuanhehe](https://github.com/sanchuanhehe)\n\n- [.github/workflows/pkg-deb.yml](../../.github/workflows/pkg-deb.yml)\n\n<br>\n\n## 支持的架构\n\n当前支持以下架构的 deb 包构建：\n\n- `amd64` (x86_64)\n\n<br>\n\n## CI 构建产物\n\n每次 CI 构建会生成：\n\n1. **deb 包文件**: `chsrc_<version>-1_<arch>.deb`\n2. **仓库元数据**: `Packages` 和 `Packages.gz` 文件用于创建 APT 仓库\n\n<br>\n\n\n## 自动触发\n\ndeb 包构建 CI 会在以下情况下自动触发：\n\n1. **Push 事件**：当 push 到 `gh-build` 分支时自动构建，并上传 deb 包 到 `pre` 这个特定的 release 中\n2. **Release 事件**: 当创建新的 release 时自动构建，并上传 deb 包到最新的这个 release 中\n2. **手动触发**: 可以在 GitHub Actions 页面手动触发构建\n\n<br>\n\n## 手动发布流程\n\n1. 确保所有代码已合并到主分支\n2. 更新版本号和 changelog\n3. 创建并推送 git tag: `git tag v1.2.3 && git push origin v1.2.3`\n4. 在 GitHub 上创建 release\n5. CI 将自动构建并上传 deb 包\n\n<br>\n"
  },
  {
    "path": "pkg/deb/Makefile",
    "content": "#!/usr/bin/make -f\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# --------------------------------------------------------------\n# Build File    : Makefile\n# File Authors  : sanchuanhehe <wyihe5520@gmail.com>\n# Contributors  :  曾奥然 <ccmywish@qq.com>\n#\t\t\t\t\t\t\t\t|\n# Created On    : <2025-06-14>\n# Last Modified : <2025-06-16>\n#\n# deb package targets\n#\n# @issue https://github.com/RubyMetric/chsrc/pull/206\n# 这些本是 debhelper 兼容性版本 (debian/compat) 为 9 时所需要定义的 targets\n# 然而现在已经为版本 13 (debian/compat已移除)，不再需要这些 targets，仅出于\n# 实用目的保留。由于以上原因，也不要修改这些 targets 的名称。\n# --------------------------------------------------------------\n\nall: deb-build\n\ndeb-prepare:\n\t@echo \"Starting: Prepare for building deb package\"\n\t@echo \"Finished: Prepare for building deb package\"\n\ndeb-build: deb-prepare\n\t@echo \"Starting: Build deb package\"\n\t@debuild -us -uc -b\n\t@echo \"Finished: Build deb package\"\n\ndeb-clean:\n\t@echo \"Starting: Clean deb build artifacts\"\n\t-@rm -rf debian/chsrc/\n\t-@rm -f ../chsrc_*.deb ../chsrc-dbgsym_*.ddeb ../chsrc_*.changes ../chsrc_*.buildinfo ../chsrc_*.build\n\t@echo \"Finished: Clean deb build artifacts\"\n\n.PHONY: deb-prepare deb-build deb-clean\n"
  },
  {
    "path": "pkg/deb/README.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : README.md\n ! Doc Authors   : sanchuanhehe <wyihe5520@gmail.com>\n !               |  曾奥然 <ccmywish@qq.com>\n ! Contributors  : Nil Null <nil@null.org>\n !               |\n ! Created On    : <2025-06-14>\n ! Last Modified : <2025-06-16>\n ! ---------------------------------------------------------- -->\n\n# deb package\n\n本文档说明了 `chsrc` 项目的 deb 包的相关情况\n\n<br>\n\n## 相关文件\n\n- `.github/workflows/pkg-deb.yml` - CI 配置文件\n- `./CI.md` - CI 情况说明\n\n<wbr>\n\n- `./debian/` - deb 包构建配置目录\n- `./BUILD.md` - 如何手动构建\n- `./Makefile` - deb 包构建 Makefile\n- `./deb-installation-test.sh` - deb 包 **已正确安装** 测试脚本\n\n<br>\n\n\n## 安装\n\n如果你是普通用户，你应该从 [GitHub Releases](https://github.com/RubyMetric/chsrc/releases) 下载合适的 deb 包，然后运行以下命令安装：\n\n```bash\nsudo dpkg -i chsrc_*.deb\nsudo apt-get install -f  # Fix any dependency issues\n```\n\n如果你是高级用户，你可以自己阅读本目录下的 [./BUILD.md](./BUILD.md) 来自己构建 deb 包并按照上述同样的方式安装。\n\n<br>\n\n\n## `debian/` 目录结构\n\n```\ndebian/\n├── changelog      # 版本更新日志\n├── compat         # debhelper 兼容性版本\n├── control        # 包控制信息和依赖\n├── copyright      # 版权信息\n├── postinst       # 安装后脚本\n├── prerm          # 卸载前脚本\n└── rules          # 构建规则\n```\n\n其中，最后三个是 `+x` 的可执行文件。\n\n<br>\n"
  },
  {
    "path": "pkg/deb/deb-installation-test.sh",
    "content": "#!/bin/bash\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# --------------------------------------------------------------\n# Test File     : deb-installation-test.sh\n# File Authors  : sanchuanhehe <wyihe5520@gmail.com>\n# Contributors  :  曾奥然 <ccmywish@qq.com>\n#               |\n# Created On    : <2025-06-14>\n# Last Modified : <2025-06-16>\n#\n# Test script for deb package installation\n# --------------------------------------------------------------\n\nset -e\n\necho \"Testing installation of deb package 'chsrc' ...\"\n\n# Test 1: Check if chsrc binary exists and is executable\nif [ ! -f \"/usr/bin/chsrc\" ]; then\n  echo \"ERROR: /usr/bin/chsrc not found\"\n  exit 1\nfi\n\nif [ ! -x \"/usr/bin/chsrc\" ]; then\n  echo \"ERROR: /usr/bin/chsrc is not executable\"\n  exit 1\nfi\n\necho \"✓ /usr/bin/chsrc binary exists and is executable\"\n\n# Test 2: Check if man page exists\nif [ ! -f \"/usr/share/man/man1/chsrc.1\" ]; then\n  echo \"WARNING: chsrc man page not found at /usr/share/man/man1/chsrc.1\"\nelse\n  echo \"✓ chsrc man page exists\"\nfi\n\n# Test 3: Test basic functionality\necho \"Testing basic chsrc functionality...\"\nif /usr/bin/chsrc help >/dev/null 2>&1; then\n  echo \"✓ command 'chsrc help' works\"\nelse\n  echo \"ERROR: command 'chsrc help' failed\"\n  exit 1\nfi\n\nif /usr/bin/chsrc list >/dev/null 2>&1; then\n  echo \"✓ command 'chsrc list' works\"\nelse\n  echo \"ERROR: command 'chsrc list' failed\"\n  exit 1\nfi\n\necho \"All installation tests of deb package 'chsrc' passed!\"\n"
  },
  {
    "path": "pkg/deb/debian/changelog",
    "content": "chsrc (0.2.3-1) unstable; urgency=medium\n\n  * v0.2.3 已发布\n\n -- 曾奥然 <ccmywish@qq.com>  Wed, 29 Oct 2025 11:29:05 +0800\n\n\nchsrc (0.1.9-1) unstable; urgency=medium\n\n  * v0.1.9 已发布\n\n -- 曾奥然 <ccmywish@qq.com>  Sun, 15 Jun 2025 13:32:50 +0800\n\n\nchsrc (0.0.1-1) unstable; urgency=medium\n\n  * 首个 deb 包已完成!\n\n -- sanchuanhehe <wyihe5520@gmail.com>  Mon, 10 Jun 2025 00:00:00 +0000\n"
  },
  {
    "path": "pkg/deb/debian/control",
    "content": "Source: chsrc\nSection: utils\nPriority: optional\nMaintainer: sanchuanhehe <wyihe5520@gmail.com>\nBuild-Depends: debhelper-compat (= 13), build-essential, libc6-dev\nStandards-Version: 4.6.0\nHomepage: https://chsrc.run/\nVcs-Git: https://github.com/RubyMetric/chsrc.git\nVcs-Browser: https://github.com/RubyMetric/chsrc\n\nPackage: chsrc\nArchitecture: any\nDepends: ${shlibs:Depends}, ${misc:Depends}\nDescription: Change Source - A tool for changing software sources\n chsrc is a command-line tool for changing software sources (mirrors)\n for various package managers and programming language ecosystems.\n It supports automatic detection and switching of sources for better\n download speeds in different regions.\n"
  },
  {
    "path": "pkg/deb/debian/copyright",
    "content": "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nUpstream-Name: chsrc\nUpstream-Contact: 曾奥然 <ccmywish@qq.com>\nSource: https://github.com/RubyMetric/chsrc\n\nFiles: *\nCopyright: 2023-2026 曾奥然 <ccmywish@qq.com>\n           2023-2026  郭恒  <2085471348@qq.com>\nLicense: GPL-3+\nComment: The authors' names are indicated in each source code file's header.\n\nFiles: lib/xy.h\nCopyright: 2023-2026 曾奥然 <ccmywish@qq.com>\n           2023-2026  郭恒  <2085471348@qq.com>\nLicense: MIT\n\nFiles: pkg/deb/debian/*\nCopyright: 2025-2026 sanchuanhehe <wyihe5520@gmail.com>\nLicense: GPL-3+\n\nLicense: GPL-3+\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n .\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n GNU General Public License for more details.\n .\n You should have received a copy of the GNU General Public License\n along with this program. If not, see <https://www.gnu.org/licenses/>.\n .\n On Debian systems, the complete text of the GNU General\n Public License version 3 can be found in \"/usr/share/common-licenses/GPL-3\".\nComment:\n On Debian systems, the full text of the GNU General Public License\n version 3 can be found in the file '/usr/share/common-licenses/GPL-3'.\n\nLicense: MIT\n MIT License\n\n Copyright (c) 2023-2026 曾奥然 (Aoran Zeng), 郭恒 (Heng Guo)\n\n Permission 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\n The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.\n\n THE 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"
  },
  {
    "path": "pkg/deb/debian/postinst",
    "content": "#!/bin/sh\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# --------------------------------------------------------------\n# deb File      : postinst\n# File Authors  : sanchuanhehe <wyihe5520@gmail.com>\n# Contributors  :   Nil Null   <nil@null.org>\n#\t              |\n# Created On    : <2025-06-14>\n# Last Modified : <2025-06-16>\n#\n# postinst script for chsrc\n# --------------------------------------------------------------\n\nset -e\n\ncase \"$1\" in\n    configure)\n        # Update man database\n        if command -v mandb >/dev/null 2>&1; then\n            mandb -q /usr/share/man/man1/chsrc.1 2>/dev/null || true\n        fi\n\n        # Make sure chsrc is executable\n        chmod +x /usr/bin/chsrc\n\n        echo \"chsrc has been successfully installed!\"\n        echo \"Run 'chsrc help' to get started.\"\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#DEBHELPER#\n\nexit 0\n"
  },
  {
    "path": "pkg/deb/debian/prerm",
    "content": "#!/bin/sh\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# --------------------------------------------------------------\n# deb File      : prerm\n# File Authors  : sanchuanhehe <wyihe5520@gmail.com>\n# Contributors  :   Nil Null   <nil@null.org>\n#\t              |\n# Created On    : <2025-06-14>\n# Last Modified : <2025-06-16>\n#\n# prerm script for chsrc\n# --------------------------------------------------------------\n\nset -e\n\ncase \"$1\" in\n    remove|upgrade|deconfigure)\n        # Nothing special to do during removal\n        ;;\n\n    failed-upgrade)\n        ;;\n\n    *)\n        echo \"prerm called with unknown argument \\`$1'\" >&2\n        exit 1\n        ;;\nesac\n\n#DEBHELPER#\n\nexit 0\n"
  },
  {
    "path": "pkg/deb/debian/rules",
    "content": "#!/usr/bin/make -f\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# --------------------------------------------------------------\n# Build File    : rules\n# File Authors  : sanchuanhehe <wyihe5520@gmail.com>\n#               |  曾奥然 <ccmywish@qq.com>\n# Contributors  : Nil Null <nil@null.org>\n#\t\t\t\t\t\t\t\t|\n# Created On    : <2025-06-14>\n# Last Modified : <2025-06-20>\n#\n# 该文件是 Makefile 格式\n# --------------------------------------------------------------\n#\n# debuild 调用 dpkg-buildpackage\n#\n# dpkg-buildpackage 通过调用 fakeroot debian/rules <target> 执行本文件\n#\n# 由于下面的 %，所有任务都将被传递给 dh\n#\n# 比如：\n#\n# \t debian/rules <target>\n#\n# 会转换为：\n#\n#\t\t\tdh <target>\n#\n# 来执行\n#\n# 简单理解，将顺序调用:\n#\t\t1. dh clean\n#\t\t2. dh build  (debian/rules override_dh_auto_build)\n#\t\t3. dh binary (debian/rules override_dh_auto_install)\n# --------------------------------------------------------------\n\n# 由于 debuild 要寻找 debian/ 目录，因此当前工作目录一定在 pkg/deb 下\nChsrc-Root-Dir = $(CURDIR)/../../\n\n%:\n\tdh $@\n\noverride_dh_auto_build:\n# 切换到 chsrc 根目录\n\t@$(MAKE) -C $(Chsrc-Root-Dir) build-in-release-mode\n\noverride_dh_auto_install:\n\t@$(MAKE) -C $(Chsrc-Root-Dir) install DESTDIR=$(CURDIR)/debian/chsrc\n"
  },
  {
    "path": "src/chsrc-main.c",
    "content": "/** ------------------------------------------------------------\n * Copyright © 2023-2026 曾奥然, 郭恒\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n *\n *                  chsrc: Change Source\n *\n *                 全平台通用换源工具与框架\n *\n *         Change Source everywhere for every software\n *\n * 项目创建者: 曾奥然, 郭恒\n * -------------------------------------------------------------\n *\n * 这是一个高度依靠贡献者的项目，我们直接把每一位贡献者写进了代码\n * 里，这是比 Git commit message 更加稳定的方式。但我们不满足于仅\n * 把大家写在注释里，因为C语言在编译时会无情地把这些信息抹去。\n *\n *           所以，我们让每一位贡献者直接参与运行时！\n *\n * 想象一下，每一位贡献者都化作一串比特，穿梭于全国各地的桌面PC中，\n * 流淌在数据中心的机房，分身在手机、路由器、小型嵌入式设备中...\n * 每当 chsrc 执行一次 recipe 相关的操作，这些比特便会复苏，贡献者\n * 的信息随之浮现。它提醒着使用者：在你与开源世界的每一次交互背后，\n * 都是许多人的协作，跨越省份与疆域，以代码相连。\n *\n * 我们希望营造像 Richard Stallman 在创建 GNU 项目之前，在 MIT 时\n * 那样的氛围 —— 写自己用得上的软件，与大家一起开发、维护，简单纯\n * 粹，无关商业利益。就像小区、校园自发组建的足球篮球队，从一次偶\n * 然的加入，逐渐成长为互相支持的伙伴。\n * ------------------------------------------------------------*/\n\n#define Chsrc_Maintain_URL   \"https://github.com/RubyMetric/chsrc\"\n#define Chsrc_Maintain_URL2  \"https://gitee.com/RubyMetric/chsrc\"\n\n#include \"framework/version.h\"\n#include \"framework/core.c\"\n#include \"framework/chef.c\"\n\nvoid\nchsrc_register_contributors ()\n{\n  /* 项目创建者 */\n  chef_register_contributor (\"@ccmywish\",       \"曾奥然\",         \"ccmywish@qq.com\",                NULL);\n  // 该 ID 为 Gitee ID\n  chef_register_contributor (\"@G_I_Y\",          \"郭恒\",           \"2085471348@qq.com\",              NULL);\n\n  /* 所有贡献者 (按参与贡献时间排序) */\n  chef_register_contributor (\"@Aaron-212\",      \"Aaron Ruan\",     \"aaron212cn@outlook.com\",         NULL);\n  chef_register_contributor (\"@chenrui333\",     \"Rui Chen\",       \"rui@chenrui.dev\",                NULL);\n  chef_register_contributor (\"@livelycode36\",   \"Shengwei Chen\",  \"414685209@qq.com\",               NULL);\n  chef_register_contributor (\"@Gn3po4g\",        \"Peng Gao\",       \"gn3po4g@outlook.com\",            NULL);\n  chef_register_contributor (\"@BlockLune\",      \"BlockLune\",      \"blocklune@gmail.com\",            NULL);\n  chef_register_contributor (\"@MrWillCom\",      \"Mr. Will\",       \"mr.will.com@outlook.com\",        NULL);\n  chef_register_contributor (\"@Jerry-Terrasse\", \"Terrasse\",       \"terrasse@qq.com\",                NULL);\n  chef_register_contributor (\"@lontten\",        \"Lontten\",        \"lontten@163.com\",                NULL);\n  chef_register_contributor (\"@happy-game\",     \"Happy Game\",     \"happygame1024@gmail.com\",        NULL);\n  chef_register_contributor (\"@Word2VecT\",      \"Word2VecT\",      \"tangzinan@bupt.edu.cn\",          NULL);\n  chef_register_contributor (\"@wickdynex\",      \"Xuan\",           \"wick.dynex@qq.com\",              NULL);\n  chef_register_contributor (\"@Efterklang\",     \"GnixAij\",        \"gaojiaxing0220@gmail.com\",       NULL);\n  chef_register_contributor (\"@czyt\",           \"czyt\",           \"czyt.go@gmail.com\",              NULL);\n  chef_register_contributor (\"@XUANJI233\",      \"XUANJI233\",      \"xuanji233@outlook.com\",          NULL);\n  chef_register_contributor (\"@Yangmoooo\",      \"Yangmoooo\",      \"yangmoooo@outlook.com\",          NULL);\n  chef_register_contributor (\"@zouri\",          \"Zouri\",          \"guoshuaisun@outlook.com\",        NULL);\n  chef_register_contributor (\"@xyx1926885268\",  \"Yongxiang\",      \"1926885268@qq.com\",              NULL);\n  chef_register_contributor (\"@YU-7\",           \"YU-7\",           \"2747046473@qq.com\",              NULL);\n  chef_register_contributor (\"@juzeon\",         \"juzeon\",         \"skyjuzheng@gmail.com\",           NULL);\n  chef_register_contributor (\"@jialinlvcn\",     \"Jialin Lyu\",     \"jialinlvcn@aliyun.com\",          NULL);\n  chef_register_contributor (\"@Kattos\",         \"ccy\",            \"icuichengyi@gmail.com\",          NULL);\n  chef_register_contributor (\"@xrgzs\",          \"MadDogOwner\",    \"xiaoran@xrgzs.top\",              NULL);\n  chef_register_contributor (\"@sanchuanhehe\",   \"sanchuanhehe\",   \"wyihe5520@gmail.com\",            NULL);\n  chef_register_contributor (\"@Mikachu2333\",    \"Mikachu2333\",    \"mikachu.23333@zohomail.com\",     NULL);\n  chef_register_contributor (\"@techoc\",         \"Rui Yang\",       \"techoc@foxmail.com\",             NULL);\n  chef_register_contributor (\"@BingChunMoLi\",   \"BingChunMoLi\",   \"bingchunmoli@bingchunmoli.com\",  NULL);\n  // 该 ID 为 Gitee ID\n  chef_register_contributor (\"@hezonglun\",      \"HeZongLun\",      \"hezonglun123456@outlook.com\",    NULL);\n  chef_register_contributor (\"@Young-Lord\",     \"LY\",             \"ly-niko@qq.com\",                 NULL);\n  chef_register_contributor (\"@MingriLingran\",  \"MingriLingran\",  \"i@linran.moe\",                   NULL);\n  chef_register_contributor (\"@usernameisnull\", \"MaBing\",         \"cumt_ttr@163.com\",               NULL);\n\n  /**\n   * AI贡献者：\n   *\n   *    ChatGPT、GitHub Copilot、DeepSeek\n   *\n   * 这几位是贡献者显式说明的，也许还有隐式使用的一些AI并没有被记录下来，可以添加在这里\n   */\n}\n\n#include \"recipe/menu.c\"\n\n#include \"rawstr4c.h\"\n\n\n\nvoid\ncli_print_available_mirrors ()\n{\n  {\n  char *msg = ENGLISH ? \"To specify a source, use chsrc set \" : \"指定使用某源，请使用 chsrc set \";\n  say (bdblue(xy_strcat (3, msg, \"<target>\", \" <code>\\n\")));\n  }\n\n  {\n  char *msg = ENGLISH ? \"Available Mirror Sites: \\n\" : \"可用镜像站: \\n\";\n  say (bdgreen(msg));\n  }\n\n  {\n  char *msg1 = ENGLISH ? \"Mirror abbr\" : \"镜像站简写\";\n  char *msg2 = ENGLISH ? \"Mirror URL\"  : \"镜像站URL\";\n  char *msg3 = ENGLISH ? \"Mirror Name\" : \"镜像站\";\n  char *format = ENGLISH ? \"  %-13s%-28s%-35s%s\\n\" : \"  %-13s%-33s%-42s%s\\n\";\n  printf (format, \"code\", msg1, msg2, msg3);\n  say    (\"---------    --------------    -------------------------------------     ---------------------\");\n  }\n\n  for (int i = 0; i < xy_c_array_len (chsrc_available_mirrors); i++)\n    {\n      MirrorSite_t *mir = chsrc_available_mirrors[i];\n      printf (\"%-14s%-18s%-41s \", mir->code, mir->abbr, mir->site); say (mir->name);\n    }\n}\n\n\n/**\n * @brief 遍历以 / 为分隔符的别名字符串，对每个别名调用回调函数\n *\n * @param  aliases    空格分隔的 alias 字符串\n * @param  callback   对每个 alias 调用的回调函数\n * @param  user_data  传递给回调函数的用户数据\n *\n * @return 如果回调函数返回true则停止遍历并返回true，否则返回false\n */\nbool\niterate_aliases (const char *aliases, bool (*callback)(const char *alias, void *user_data), void *user_data)\n{\n  char *aliases_copy = xy_strdup (aliases);\n  char *tok_start = aliases_copy;\n  char *cursor;\n  bool result = false;\n\n  while (*tok_start != '\\0')\n    {\n      cursor = tok_start;\n      while (*cursor != '/' && *cursor != '\\0') cursor++;\n\n      // 结束当前token\n      char space_or_eos = *cursor;\n      *cursor = '\\0';\n\n      // 调用回调函数\n      if (callback(tok_start, user_data))\n        {\n          result = true;\n          break;\n        }\n\n      *cursor = space_or_eos;\n      if (space_or_eos == '\\0') { break; }\n      tok_start = cursor+1;\n    }\n\n  return result;\n}\n\n\n/**\n * 用于 cli_print_targets_for_menu 的回调函数，打印每个别名\n */\nbool\ncallback_print_alias (const char *alias, void *user_data)\n{\n  printf (\"%s  \", alias);\n  return false; // 继续遍历，不停止\n}\n\nvoid\ncallback_print_targets (void *data, void *DUMMY)\n{\n  Target_t *target = (Target_t *) data;\n  // 使用通用的别名遍历函数打印所有别名\n  iterate_aliases (target->aliases, callback_print_alias, NULL);\n  br(); // 每个target换行\n}\n\nvoid\ncli_print_targets_for_menu (XySeq_t *menu)\n{\n  xy_seq_each (menu, callback_print_targets, NULL);\n  br(); // 最后额外换行\n}\n\nvoid\ncli_print_supported_targets ()\n{\n  {\n  char *msg = ENGLISH ? \"Support following targets (same line indicates these targets are compatible)\"\n                      : \"支持对以下目标换源 (同一行表示这几个命令兼容)\" ;\n  say (bdblue(msg)); br();\n  }\n\n  {\n  char *msg = ENGLISH ? \"Programming Languages\" : \"编程语言\";\n  say (bdgreen(msg));\n  say (\"-------------------------\");\n  cli_print_targets_for_menu (ProgStore.pl);\n  }\n\n  {\n  char *msg = ENGLISH ? \"Operating Systems\" : \"操作系统\";\n  say (bdgreen(msg));\n  say (\"-------------------------\");\n  cli_print_targets_for_menu (ProgStore.os);\n  }\n\n  {\n  char *msg = ENGLISH ? \"Softwares\" : \"软件\";\n  say (bdgreen(msg));\n  say (\"-------------------------\");\n  cli_print_targets_for_menu (ProgStore.wr);\n  }\n}\n\nvoid\ncli_print_menu (char *menu)\n{\n  if (xy_streql (menu, \"pl\"))\n    {\n      char *msg =\n        ENGLISH ? \"Support following Programming Languages (same line indicates these targets are compatible)\\n\"\n                : \"支持对以下编程语言生态换源 (同一行表示这几个目标兼容)\\n\";\n      say (bdgreen(msg));\n      cli_print_targets_for_menu (ProgStore.pl);\n    }\n  else if (xy_streql (menu, \"os\"))\n    {\n      char *msg =\n        ENGLISH ? \"Support following Operating Systems (same line indicates these targets are compatible)\\n\"\n                : \"支持对以下操作系统换源 (同一行表示这几个目标兼容)\\n\";\n      say (bdgreen(msg));\n      cli_print_targets_for_menu (ProgStore.os);\n    }\n  else if (xy_streql (menu, \"wr\"))\n    {\n      char *msg =\n        ENGLISH ? \"Support following Softwares (same line indicates these targets are compatible)\\n\"\n                : \"支持对以下软件换源 (同一行表示这几个目标兼容)\\n\";\n      say (bdgreen(msg));\n      cli_print_targets_for_menu (ProgStore.wr);\n    }\n}\n\n\n\n/**\n * 用于 chsrc list <target>\n */\nvoid\ncli_print_target_available_sources (Source_t sources[], size_t size)\n{\n  for (int i=0;i<size;i++)\n    {\n      Source_t src = sources[i];\n      const MirrorSite_t *mir = src.mirror;\n      if (NULL == src.url)\n        {\n          src.url = \"Please help to add the upstream url!\";\n        }\n      printf (\"%-14s%-18s%-50s \", mir->code, mir->abbr, src.url);\n      say (mir->name);\n    }\n}\n\n\nvoid\ncli_print_target_features (Target_t *target, const char *input_target_name)\n{\n  {\n  char *msg = ENGLISH ? \"\\nAvailable Features:\\n\" : \"\\n可用功能:\\n\";\n  say (bdgreen(msg));\n  }\n\n  {\n  char *msg = ENGLISH ? \" Get: View the current source state \" : \" Get: 查看当前源状态 \";\n  char *get_msg = xy_strcat (3, msg, \"| chsrc get \", input_target_name);\n  if (target->getfn != NULL) printf (\" %s%s\\n\", bdgreen(YesMark), purple(get_msg));\n  else printf (\" %s%s\\n\", bdred(NoMark), get_msg);br();\n  }\n\n  {\n  char *msg = ENGLISH ? \" Reset: Reset to the default source \" : \" Reset: 重置回默认源 \";\n  char *reset_msg = xy_strcat (3, msg, \"| chsrc reset \", input_target_name);\n  if (target->resetfn != NULL) printf (\" %s%s\\n\", bdgreen(YesMark), purple(reset_msg));\n  else printf (\" %s%s\\n\", bdred(NoMark), reset_msg);br();\n  }\n\n  {\n  char *msg = ENGLISH ? \" UserDefine: using user-defined source link \" : \" UserDefine: 用户自定义换源链接 \";\n  char *user_define_msg = xy_strcat (5, msg, \"| chsrc set \", input_target_name, \" https://user-define-url.org/\", input_target_name);\n  if (target->can_user_define) printf (\" %s%s\\n\", bdgreen(YesMark), purple(user_define_msg));\n  else printf (\" %s%s\\n\", bdred(NoMark), user_define_msg);br();\n  }\n\n  {\n  char *scope_msg = NULL;\n\n  for (int i=0; i<NumberOfScopeType; i++)\n    {\n      ScopeCapability_t cap = target->scope_caps[i];\n      char *scope_name;\n      if (i == 0)\n        {\n          scope_name = CHINESE ? \" 项目级换源\" : \" project scope\";\n          scope_msg = xy_strcat (3, scope_name, \" | chsrc set -scope=project \", input_target_name);\n        }\n      else if (i == 1)\n        {\n          scope_name = CHINESE ? \" 用户级换源\" : \" user scope\";\n          scope_msg = xy_strcat (3, scope_name, \" | chsrc set -scope=user    \", input_target_name);\n        }\n      else if (i == 2)\n        {\n          scope_name = CHINESE ? \" 系统级换源\" : \" system scope\";\n          scope_msg = xy_strcat (3, scope_name, \" | chsrc set -scope=system  \", input_target_name);\n        }\n      else\n        {\n          xy_unreached();\n        }\n\n      char *msg = NULL;\n      switch (cap)\n        {\n        case ScopeCap_Unknown:\n          msg = xy_strcat (6, \" \", bdred(NoMark), scope_msg, \" (\", \"是否支持该作用域尚不了解，欢迎贡献\", \")\");\n          puts (msg);\n          break;\n        case ScopeCap_Unable:\n          msg = xy_strcat (6, \" \", bdred(NoMark), scope_msg, \" (\", \"不支持\", \")\");\n          puts (msg);\n          break;\n        case ScopeCap_Able_But_Not_Implemented:\n          msg = xy_strcat (6, \" \", bdyellow(HalfYesMark), scope_msg, \" (\", \"支持但未实现\", \")\");\n          puts (msg);\n          break;\n        case ScopeCap_Able_And_Implemented:\n          msg = xy_strcat (3, \" \", bdgreen(YesMark),\n            purple (xy_strcat (4, scope_msg, \" (\", \"支持且已实现\", \")\")));\n          puts (msg);\n          break;\n        default:\n          xy_unreached();\n        }\n    }\n    Scope_t default_scope = target->default_scope;\n    char *default_scope_name = NULL;\n    switch (default_scope)\n      {\n      case ProjectScope:\n        default_scope_name = CHINESE ? \"项目级\" : \"Project Scope\";\n        break;\n      case UserScope:\n        default_scope_name = CHINESE ? \"用户级\" : \"User Scope\";\n        break;\n      case SystemScope:\n        default_scope_name = CHINESE ? \"系统级\" : \"System Scope\";\n        break;\n      case ImplementationDefinedScope:\n        default_scope_name = CHINESE ? \"由实现定义\" : \"Implementation Defined Scope\";\n        break;\n      default:\n        xy_unreached();\n      }\n    char *msg = xy_strcat (3, bdblue (\" = \"),\n      purple (xy_strcat (5, \"默认作用域 | chsrc set -scope=default \", input_target_name, \" (= \", default_scope_name ,\")\")));\n    puts (msg);\n    br();\n  }\n\n  {\n  char *msg = ENGLISH ? \" English: Output in English \" : \" English: 英文输出 \";\n  char *english_msg = xy_strcat (3, msg, \"| chsrc set -en \", input_target_name);\n  if (target->can_english) printf (\" %s%s\\n\", bdgreen(YesMark), purple(english_msg));\n  else printf (\" %s%s\\n\", bdred(NoMark), english_msg);br();\n  }\n\n  if (target->note)\n    {\n      char *msg = ENGLISH ? \"NOTE: \" : \"备注: \";\n      printf (\"%s%s\\n\\n\", bdyellow (msg), bdyellow (target->note));\n    }\n}\n\n\n/**\n * @brief 简略打印维护信息\n *\n * 用于 chsrc get/set/reset <target>\n */\nvoid\ncli_print_target_maintain_info_briefly (Target_t *target, const char *input_target_name)\n{\n  if (target->sources_last_updated)\n    {\n      char *msg = ENGLISH ? \"Ingredient(Sources) Last Updated: \" : \"食源检查: \";\n      printf (\"%s%s  \", msg, purple(target->sources_last_updated));\n    }\n\n  if (target->last_updated)\n    {\n      char *msg = ENGLISH ? \"Recipe Last Updated: \" : \"食谱更新: \";\n      printf (\"%s%s  \", msg, purple(target->last_updated));\n    }\n\n  char num[32]; sprintf(num, \"%d\", target->cooks_n + target->sauciers_n);\n  char *msg = ENGLISH ? \"Contributors: \" : \"后厨人数: \";\n  printf (\"%s%s  \", msg, purple(num));\n\n  msg = ENGLISH ? xy_strcat (3, \"(See chsrc ls \",  input_target_name, \")\")\n                : xy_strcat (3, \"(详查 chsrc ls \", input_target_name, \")\");\n  printf (\"%s\\n\", msg);\n}\n\n\n/**\n * @brief 详细打印维护信息\n *\n * 用于 chsrc ls <target>\n */\nvoid\ncli_print_target_maintain_info (Target_t *target, const char *input_target_name)\n{\n  if (target->created_on)\n    {\n      char *msg = ENGLISH ? \"Recipe Created On: \" : \"食谱创建: \";\n      printf (\"%s%s \", bdblue(msg), target->created_on);\n    }\n\n  if (target->last_updated)\n    {\n      char *msg = ENGLISH ? \"Recipe Last Updated: \" : \"食谱更新: \";\n      printf (\"%s%s \", bdblue(msg), target->last_updated);\n    }\n\n  if (target->sources_last_updated)\n    {\n      char *msg = ENGLISH ? \"Ingredient(Sources) Last Updated: \" : \"食源检查: \";\n      printf (\"%s%s\\n\", bdblue(msg), target->sources_last_updated);\n    }\n\n  {\n    char *msg = ENGLISH ? \"Current Chef: \" : \"品控: \";\n    if (target->chef)\n      {\n        printf (\"%s%s <%s>\\n\", bdblue(msg),\n                target->chef->name  ? target->chef->name  : \"Unknown\",\n                target->chef->email ? target->chef->email : \"unknown@example.com\");\n      }\n    else\n      {\n        char *msg1 = CHINESE ? \"该 recipe 的负责人暂空缺, 欢迎担任\" : \"Vacant, Welcome to hold the position\";\n        printf (\"%s%s\\n\", bdblue(msg), bdgreen(msg1));\n      }\n  }\n\n\n  {\n    char *msg = ENGLISH ? \"Cooks: \" : \"掌勺: \";\n    if (target->cooks && target->cooks_n > 0)\n      {\n        printf (\"%s\", bdblue(msg));\n        for (size_t i = 0; i < target->cooks_n; i++)\n          {\n            if (i > 0) printf (\", \");\n            printf (\"%s <%s>\",\n                    target->cooks[i]->name  ? target->cooks[i]->name : \"Unknown\",\n                    target->cooks[i]->email ? target->cooks[i]->email : \"unknown@example.com\");\n          }\n        printf (\"\\n\");\n      }\n    else\n      {\n        char *msg1 = CHINESE ? \"暂空缺, 欢迎担任\" : \"Vacant, Welcome to hold the position\";\n        printf (\"%s%s\\n\", bdblue(msg), bdgreen(msg1));\n      }\n  }\n\n  {\n    char *msg = ENGLISH ? \"Sauciers: \" : \"调味: \";\n    if (target->sauciers && target->sauciers_n > 0)\n      {\n        printf (\"%s\", bdblue(msg));\n        for (size_t i = 0; i < target->sauciers_n; i++)\n          {\n            if (i > 0) printf (\", \");\n            printf (\"%s <%s>\", target->sauciers[i]->name, target->sauciers[i]->email );\n          }\n        br();\n      }\n    else\n      {\n        char *msg1 = CHINESE ? \"暂空缺, 欢迎参与贡献\" : \"Vacant, Welcome to contribute!\";\n        printf (\"%s%s\\n\", bdblue(msg), bdgreen(msg1));\n      }\n  }\n}\n\n\nvoid\ncli_print_version ()\n{\n  char *version_string = \"v\" Chsrc_Version \" (\" Chsrc_Release_Date \")\";\n\n  char *str = xy_str_gsub (CHINESE ? RAWSTR_chsrc_for_v_CHINESE : RAWSTR_chsrc_for_v_ENGLISH,\n                           \"@ver@\", version_string);\n  println (str);\n}\n\n\nvoid\ncli_print_help ()\n{\n  char *version_string = \"v\" Chsrc_Version \" (\" Chsrc_Release_Date \")\";\n\n  const char *raw = CHINESE ? RAWSTR_chsrc_USAGE_CHINESE : RAWSTR_chsrc_USAGE_ENGLISH;\n\n  char *str = xy_str_gsub (raw, \"@ver@\", version_string);\n  println (str);\n}\n\n\nvoid\ncli_print_issues ()\n{\n  println (RAWSTR_chsrc_for_issue);\n\n  /*\n  if (chsrc_check_program (\"gh\"))\n    {\n      char *cmd = xy_quiet_cmd (\"gh browse --repo RubyMetric/chsrc\");\n      system (cmd);\n    }\n  */\n}\n\n\n/**\n * @brief 用于 callback_find_target() 的回调函数，检查别名是否匹配用户输入\n */\nbool\ncallback_match_alias (const char *alias, void *user_data)\n{\n  const char *input = (const char *)user_data;\n  return xy_streql_ic (input, alias);\n}\n\n/**\n * @brief 用于 iterate_menu() 的回调函数\n */\nbool\ncallback_is_one_of_target_aliases (void *data, void *input)\n{\n  Target_t *target = (Target_t *) data;\n  if (iterate_aliases (target->aliases, callback_match_alias, input))\n    {\n      target->preludefn();\n      return true;\n    }\n  else\n    return false;\n}\n\n/**\n * 查询用户输入 `input` 是否与该 `menu` 中的某个 target 匹配\n * 若匹配将直接调用 prelude\n *\n * @param[in]   menu    menu\n * @param[in]   input   用户输入的目标名\n * @param[out]  target  返回匹配到的 Target_t 指针\n *\n * @return 匹配到则返回true，未匹配到则返回false\n */\nbool\niterate_menu (XySeq_t *menu, const char *input, Target_t **target)\n{\n  Target_t *t = xy_seq_find (menu, callback_is_one_of_target_aliases, (void *) input);\n\n  if (t)\n    {\n      *target = t;\n      t->preludefn();\n      return true;\n    }\n  else\n    {\n      *target = NULL;\n      return false;\n    }\n}\n\n\nvoid\ncallback_perform_all_prelude_for_menu (void *data, void *DUMMY)\n{\n  Target_t *target = (Target_t *) data;\n\n  if (!target->preludefn)\n    {\n      chef_debug_target (target);\n      chsrc_panic (\"未定义 _prelude() !\");\n    }\n\n  target->preludefn();\n}\n\n/**\n * @brief 用于检查所有 _prelude() 是否能正常工作\n *\n * 为了防止 DEBUG 模式下运行流程和普通模式下运行流程不一样，我们只在 Get, Set, Reset\n * 之后才运行该函数\n */\nvoid\nchsrc_perform_all_prelude ()\n{\n  chsrc_debug (\"prelude\", \"DEBUG模式下, 额外检查所有 _prelude() 是否能正常工作\");\n  xy_seq_each (ProgStore.pl, callback_perform_all_prelude_for_menu, NULL);\n  xy_seq_each (ProgStore.os, callback_perform_all_prelude_for_menu, NULL);\n  xy_seq_each (ProgStore.wr, callback_perform_all_prelude_for_menu, NULL);\n}\n\n\n/**\n * @brief 在必要的时期，最后告诉用户一些信息\n */\nvoid\nchsrc_op_epilogue ()\n{\n  br();\n  chsrc_note2 (RAWSTR_chsrc_op_epilogue);\n}\n\n\n\ntypedef enum {\n  TargetOp_Get_Source = 1,\n  TargetOp_Set_Source,\n  TargetOp_Reset_Source,\n  TargetOp_Measure_Source,\n  TargetOp_List_Config\n} TargetOp;\n\n/**\n * 寻找target，并根据 `code` 执行相应的操作\n *\n * @param  input   用户输入的目标\n * @param  code    对target要执行的操作\n * @param  option  额外的指示，可为NULL\n *\n * @return 找到目标返回true，未找到返回false\n */\nbool\nget_target (const char *input, TargetOp code, char *option)\n{\n  chsrc_register_contributors ();\n\n  Target_t *target = NULL;\n\n           bool matched = iterate_menu (ProgStore.pl, input, &target);\n  if (!matched) matched = iterate_menu (ProgStore.os, input, &target);\n  if (!matched) matched = iterate_menu (ProgStore.wr, input, &target);\n\n  if (!matched) return false;\n\n  if (TargetOp_Set_Source==code)\n    {\n      if (target->setfn)\n        {\n          /* Hook时机: 开始运行前可以在这里进行一些拦截操作 */\n          chsrc_check_scope_capability (target); /* 用户要求设置的作用域，真的能够执行吗？ */\n          target->setfn(option);\n        }\n      else chsrc_error (xy_strcat (3, \"暂未对 \", input, \" 实现 set 功能，邀您帮助: chsrc issue\"));\n    }\n  else if (TargetOp_Reset_Source==code)\n    {\n      if (target->resetfn)\n        {\n          target->resetfn(option);\n        }\n      else chsrc_error (xy_strcat (3, \"暂未对 \", input, \" 实现 reset 功能，邀您帮助: chsrc issue\"));\n    }\n  else if (TargetOp_Get_Source==code)\n    {\n      if (target->getfn)\n        {\n          target->getfn(\"\");\n        }\n      else chsrc_error (xy_strcat (3, \"暂未对 \", input, \" 实现 get 功能，邀您帮助: chsrc issue\"));\n    }\n  else if (TargetOp_List_Config==code)\n    {\n      {\n      char *msg = ENGLISH ? \"To specify a source, use chsrc set \" : \"指定使用某源，请使用 chsrc set \";\n      say (bdblue(xy_strcat (3, msg, input, \" <code>\\n\")));\n      }\n\n      {\n      char *msg = ENGLISH ? \"Available Sources: \\n\" : \"可用源: \\n\";\n      say (bdgreen(msg));\n      }\n\n      {\n      char *msg1 = ENGLISH ? \"Mirror abbr\" : \"镜像站简写\";\n      char *msg2 = ENGLISH ? \"Source URL\"  : \"换源链接\";\n      char *msg3 = ENGLISH ? \"Mirror Name\" : \"镜像站\";\n      char *format = ENGLISH ? \"  %-13s%-33s%-38s%s\\n\" : \"  %-13s%-36s%-46s%s\\n\";\n      printf (format, \"code\", msg1, msg2, msg3);\n      say    (\"---------    --------------    -----------------------------------------------    ---------------------\");\n      }\n\n      cli_print_target_available_sources (target->sources, target->sources_n);\n      cli_print_target_features (target, input);\n\n      {\n      char *msg = ENGLISH ? \"Maintainer Information:\\n\" : \"维护信息:\\n\";\n      say (bdgreen(msg));\n      cli_print_target_maintain_info (target, input);\n      }\n    }\n  else if (TargetOp_Measure_Source==code)\n    {\n      auto_select_mirror (target->sources, target->sources_n, input);\n      return true;\n    }\n\n  /* 简短显示维护信息 */\n  if (TargetOp_Get_Source==code || TargetOp_Set_Source==code || TargetOp_Reset_Source==code)\n    {\n      cli_print_target_maintain_info_briefly (target, input);\n    }\n\n  if (TargetOp_Set_Source==code || TargetOp_Measure_Source==code)\n    {\n      // 2025-09-19: 已告知该消息给用户一个多月，我们不再告知\n      // chsrc_op_epilogue ();\n    }\n\n#ifdef XY_DEBUG\n  chef_debug_target (target);\n  chsrc_perform_all_prelude ();\n#endif\n\n  return true;\n}\n\n\n\nint\nmain (int argc, char const *argv[])\n{\n  chsrc_init_framework ();\n  chsrc_init_menu ();\n\n  argc -= 1;\n\n  if (0==argc)\n    {\n      cli_print_help ();\n      return Exit_OK;\n    }\n\n  const char *command = argv[1];\n\n  // chsrc set target mirror\n  //        1    2      3\n  int cli_arg_Target_pos = 2;\n  int cli_arg_Mirror_pos = cli_arg_Target_pos + 1;\n  const char *target = NULL;\n\n  /**\n   * (1)\n   * chsrc set -scope=project -en target mirror\n   *        1        2         3     4      5\n   * argc = 5\n   *\n   * (2) 考虑到这种情况，i必须还是从1开始\n   * chsrc -en -h\n   *        1  2\n   *\n   * argc = 2\n   */\n  /* 从第一个参数遍历到最后一个参数 */\n  for (int i=1; i<=argc; i++)\n    {\n      if (xy_str_start_with (argv[i], \"-\"))\n        {\n          if (xy_streql (argv[i], \"-ipv6\"))\n            {\n              ProgMode.Ipv6Mode = true;\n            }\n          else if (xy_streql (argv[i], \"-local\"))\n            {\n              ProgMode.Scope = ProjectScope;\n              char *msg = CHINESE ? \" -local 选项已弃用，请使用 -scope=project\"\n                                  : \" -local is deprecated, please use -scope=project\";\n              chsrc_warn (msg);\n            }\n          else if (xy_str_start_with (argv[i], \"-scope\"))\n            {\n              const char *scope = NULL;\n              if (xy_streql (argv[i], \"-scope\"))\n                {\n                  scope = argv[i+1];\n                  cli_arg_Target_pos++;\n                  cli_arg_Mirror_pos++;\n                }\n              else if (xy_str_start_with (argv[i], \"-scope=\"))\n                {\n                  scope = argv[i] + 7;\n                }\n              if (xy_streql_ic (scope, \"project\"))\n                {\n                  ProgMode.Scope = ProjectScope;\n                }\n              else if (xy_streql_ic (scope, \"user\"))\n                {\n                  ProgMode.Scope = UserScope;\n                }\n              else if (xy_streql_ic (scope, \"system\"))\n                {\n                  ProgMode.Scope = SystemScope;\n                }\n              else if (xy_streql_ic (scope, \"default\"))\n                {\n                  ProgMode.Scope = ImplementationDefinedScope;\n                }\n              else\n                {\n                  if (ENGLISH)\n                    {\n                      char *msg = \"Invalid scope: \";\n                      chsrc_error (xy_strcat (3, msg, scope, \". Valid scopes are: default, project, user, system\"));\n                    }\n                  else\n                    {\n                      char *msg = \"无效的换源作用域: \";\n                      chsrc_error (xy_strcat (4, msg, scope, \"。\", \"有效的换源作用域为: default, project, user, system\"));\n                    }\n                  return Exit_Unknown;\n                }\n            }\n          else if (xy_streql (argv[i], \"-en\") || xy_streql (argv[i], \"-english\"))\n            {\n              ProgMode.EnglishMode = true;\n            }\n          else if (xy_streql (argv[i], \"-dry\"))\n            {\n              ProgMode.DryRunMode = true;\n            }\n          else if (xy_streql (argv[i], \"-no-color\") || xy_streql (argv[i], \"-no-colour\"))\n            {\n              ProgMode.NoColorMode = true;\n              xy.enable_color = false;\n            }\n          else if (    xy_streql (argv[i], \"-h\")\n                    || xy_streql (argv[i], \"-help\")\n                    || xy_streql (argv[i], \"--help\"))\n            {\n              command = \"help\"; /* 交到下方处理 */\n            }\n          else if (    xy_streql (argv[i], \"-v\")\n                    || xy_streql (command, \"-version\")\n                    || xy_streql (command, \"--version\"))\n            {\n              command = \"version\"; /* 交到下方处理 */\n            }\n          else\n            {\n              char *msg = ENGLISH ? \"Unknown option: \" : \"未识别的命令行选项 \";\n              chsrc_error (xy_2strcat (msg, argv[i])); return Exit_Unknown;\n            }\n          cli_arg_Target_pos++;\n          cli_arg_Mirror_pos++;\n        }\n    }\n\n\n  bool matched = false;\n\n  if (in_dry_run_mode())\n    {\n      char *dry_msg = ENGLISH ? \"Enable [Dry Run] mode. \"\n                                \"Simulate the source changing process (skipping speed measurement). \"\n                                \"Commands only print but don't run\\n\"\n                              : \"开启Dry Run模式，模拟换源过程(跳过测速)，命令仅打印并不运行\\n\";\n      chsrc_log (bdyellow(dry_msg));\n    }\n\n  /* chsrc help */\n  if (   xy_streql (command, \"h\")\n      || xy_streql (command, \"-h\")\n      || xy_streql (command, \"help\")\n      || xy_streql (command, \"-help\")\n      || xy_streql (command, \"--help\"))\n    {\n      cli_print_help ();\n      return Exit_OK;\n    }\n\n  /* chsrc -v */\n  else if (   xy_streql (command, \"-v\")\n           || xy_streql (command, \"-version\")\n           || xy_streql (command, \"--version\")\n           || xy_streql (command, \"ver\")\n           || xy_streql (command, \"version\"))\n    {\n      cli_print_version ();\n      return Exit_OK;\n    }\n\n  /* chsrc list */\n  else if (   xy_streql (command, \"list\")\n           || xy_streql (command, \"l\")\n           || xy_streql (command, \"ls\"))\n    {\n      if (argc < cli_arg_Target_pos)\n        {\n          cli_print_available_mirrors ();\n          br();\n          cli_print_supported_targets ();\n        }\n      else\n        {\n          target = argv[cli_arg_Target_pos];\n          if (   xy_streql (target, \"mirrors\")\n              || xy_streql (target, \"mirror\"))\n            {\n              cli_print_available_mirrors ();\n              return Exit_OK;\n            }\n\n          else if (   xy_streql (target, \"targets\")\n                   || xy_streql (target, \"target\"))\n            {\n              cli_print_supported_targets ();\n              return Exit_OK;\n            }\n\n          else if (xy_streql (target, \"os\"))\n            {\n              cli_print_menu (\"os\");\n              return Exit_OK;\n            }\n\n          else if (   xy_streql (target, \"lang\")\n                   || xy_streql (target, \"pl\")\n                   || xy_streql (target, \"language\"))\n            {\n              cli_print_menu (\"pl\");\n              return Exit_OK;\n            }\n\n          else if (   xy_streql (target, \"ware\")\n                   || xy_streql (target, \"software\"))\n            {\n              cli_print_menu (\"wr\");\n              return Exit_OK;\n            }\n\n          matched = get_target (target, TargetOp_List_Config, NULL);\n          if (!matched) goto not_matched;\n        }\n      return Exit_OK;\n  }\n\n#define MSG_EN_USE_LIST_TARGETS \"Use `chsrc list targets` to see all supported targets\"\n#define MSG_CN_USE_LIST_TARGETS \"使用 chsrc list targets 查看所有支持的目标\"\n\n  /* chsrc measure */\n  else if (   xy_streql (command, \"measure\")\n           || xy_streql (command, \"mea\")\n           || xy_streql (command, \"m\")\n           || xy_streql (command, \"cesu\")\n           || xy_streql (command, \"ce\")\n           || xy_streql (command, \"c\"))\n    {\n      if (argc < cli_arg_Target_pos)\n        {\n          char *msg = ENGLISH ? \"Please provide the target name you want to measure. \" MSG_EN_USE_LIST_TARGETS\n                              : \"请提供想要测速源的目标名。\" MSG_CN_USE_LIST_TARGETS;\n          chsrc_error (msg);\n          return Exit_Unknown;\n        }\n      ProgMode.MeasureMode = true;\n      target = argv[cli_arg_Target_pos];\n      matched = get_target (target, TargetOp_Measure_Source, NULL);\n      if (!matched) goto not_matched;\n      return Exit_OK;\n    }\n\n\n  /* chsrc get */\n  else if (   xy_streql (command, \"get\")\n           || xy_streql (command, \"g\"))\n    {\n      if (argc < cli_arg_Target_pos)\n        {\n          char *msg = ENGLISH ? \"Please provide the target name you want to view the source. \" MSG_EN_USE_LIST_TARGETS\n                              : \"请提供想要查看源的目标名。\" MSG_CN_USE_LIST_TARGETS;\n          chsrc_error (msg);\n          return Exit_Unknown;\n        }\n      target = argv[cli_arg_Target_pos];\n      matched = get_target (target, TargetOp_Get_Source, NULL);\n      if (!matched) goto not_matched;\n      return Exit_OK;\n    }\n\n  /* chsrc set */\n  else if (   xy_streql (command, \"set\")\n           || xy_streql (command, \"s\"))\n    {\n      if (argc < cli_arg_Target_pos)\n        {\n          char *msg = ENGLISH ? \"Please provide the target name you want to set the source. \" MSG_EN_USE_LIST_TARGETS\n                              : \"请提供想要设置源的目标名。\" MSG_CN_USE_LIST_TARGETS;\n          chsrc_error (msg);\n          return Exit_Unknown;\n        }\n\n      target = argv[cli_arg_Target_pos];\n      char *mirrorCode_or_url = NULL;\n      if (argc >= cli_arg_Mirror_pos)\n        {\n          mirrorCode_or_url = xy_strdup (argv[cli_arg_Mirror_pos]);\n        }\n\n      matched = get_target (target, TargetOp_Set_Source, mirrorCode_or_url);\n      if (!matched) goto not_matched;\n      return Exit_OK;\n    }\n\n  /* chsrc reset */\n  else if (   xy_streql (command, \"reset\")\n           || xy_streql (command, \"rest\")\n           || xy_streql (command, \"r\"))\n    {\n      if (argc < cli_arg_Target_pos)\n        {\n          char *msg = ENGLISH ? \"Please provide the target name you want to reset the source. \" MSG_EN_USE_LIST_TARGETS\n                              : \"请提供想要重置源的目标名。\" MSG_CN_USE_LIST_TARGETS;\n          chsrc_error (msg);\n          return Exit_Unknown;\n        }\n\n      ProgMode.ResetMode = true;\n      target = argv[cli_arg_Target_pos];\n      matched = get_target (target, TargetOp_Reset_Source, NULL);\n      if (!matched) goto not_matched;\n      return Exit_OK;\n    }\n\n  /* chsrc issue */\n  else if (   xy_streql (command, \"issue\")\n           || xy_streql (command, \"issues\")\n           || xy_streql (command, \"isue\")\n           || xy_streql (command, \"i\"))\n    {\n      cli_print_issues ();\n      return Exit_OK;\n    }\n\n  else\n    {\n      char *msg1 = ENGLISH ? \"Unknown command `\" : \"不支持的命令 \";\n      char *msg2 = ENGLISH ? \"`. Use `chsrc help` to view usage\" : \". 请使用 chsrc help 查看使用方式\";\n      chsrc_error (xy_strcat (3, msg1, command, msg2));\n      return Exit_Unknown;\n    }\n\nnot_matched:\n  if (!matched)\n    {\n      char *msg = ENGLISH ? \"Unknown target. \"  MSG_EN_USE_LIST_TARGETS\n                          : \"暂不支持的换源目标。\" MSG_CN_USE_LIST_TARGETS;\n      chsrc_error (msg);\n      return Exit_Unknown;\n    }\n}\n"
  },
  {
    "path": "src/framework/chef.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Name     : chef.c\n * File Authors  : @ccmywish\n * Contributors  : @BingChunMoLi\n * Created On    : <2025-08-09>\n * Last Modified : <2026-02-24>\n *\n * chef DSL: for chefs (recipe makers) to define a target\n * ------------------------------------------------------------*/\n\n#pragma once\n\nvoid\nchef_debug_target (Target_t *target)\n{\n#ifdef XY_DEBUG\n  if (!target)\n    {\n      chsrc_debug2 (\"target\", \"Target is NULL\");\n      return;\n    }\n\n  say (\"DEBUG Target Information:\");\n  printf (\"  Aliases: %s\\n\", target->aliases);\n\n  printf (\"  Get Function: %p\\n\", target->getfn);\n  printf (\"  Set Function: %p\\n\", target->setfn);\n  printf (\"  Reset Function: %p\\n\", target->resetfn);\n  printf (\"  Prelude Function: %p\\n\", target->preludefn);\n\n  printf (\"  Inited?: %d\\n\", target->inited);\n\n  printf (\"  Sources: %p\\n\", target->sources);\n  printf (\"  Sources Count: %d\\n\", target->sources_n);\n\n  printf (\"  Chef: %p\\n\", target->chef);\n  printf (\"  Cooks: %p\\n\", target->cooks);\n  printf (\"  Cooks Count: %d\\n\", target->cooks_n);\n  printf (\"  Sauciers: %p\\n\", target->sauciers);\n  printf (\"  Sauciers Count: %d\\n\", target->sauciers_n);\n#endif\n}\n\n\nvoid\nchef_debug_contributor (Contributor_t *contributor)\n{\n#ifdef XY_DEBUG\n  if (!contributor)\n    {\n      chsrc_debug2 (\"contrib\", \"Contributor is NULL\");\n      return;\n    }\n\n  say (\"DEBUG Contributor Information:\");\n  printf (\"  ID:    %s\\n\", contributor->id);\n  printf (\"  Name:  %s\\n\", contributor->name);\n  printf (\"  Email: %s\\n\", contributor->email);\n  printf (\"  DisplayName: %s\\n\", contributor->display_name);\n#endif\n}\n\n\n/**\n * @brief 登记所有贡献者\n *\n * @param     id       贡献者 ID，这个ID最好是GitHub用户名，但也可以不是，只需要在 chsrc 内部进行区分即可\n * @param display_name 如果没有提供该参数，则使用 name\n */\nvoid\nchef_register_contributor (char *id, char *name, char *email, char *display_name)\n{\n  if (!id || !name || !email)\n    xy_unreached();\n\n  Contributor_t *contributor = xy_malloc0 (sizeof (Contributor_t));\n  contributor->id = xy_strdup (id);\n  contributor->name = xy_strdup (name);\n  contributor->email = xy_strdup (email);\n\n  if (!display_name)\n    contributor->display_name = xy_strdup (name);\n  else\n    contributor->display_name = xy_strdup (display_name);\n\n  xy_map_set (ProgStore.contributors, id, contributor);\n}\n\n\n/**\n * @brief 修改 Provider 的测速地址\n *\n * @note 这个修改的是全局 Provider 里的信息。往往用来设置 UpstreamProvider\n */\nvoid\nchef_set_provider_smURL (SourceProvider_t *provider, char *url)\n{\n  provider->psmi.skip = NotSkip;\n  provider->psmi.url = xy_strdup (url);\n  chsrc_debug (\"m\", xy_strcat (4, \"recipe 重新为 \", provider->code, \"(镜像站信息本身) 设置测速链接: \", url));\n}\n\n\n/**\n * @brief 修改 Provider 的测速精度\n *\n * @note 这个修改的是全局 Provider 里的信息。往往用来设置 UpstreamProvider\n */\nvoid\nchef_set_provider_sm_accuracy (SourceProvider_t *provider, bool accuracy)\n{\n  provider->psmi.accurate = accuracy;\n  chsrc_debug (\"m\", xy_strcat (4, \"recipe 重新为 \", provider->code, \"(镜像站信息本身) 设置测速精度: \", accuracy ? \"精准\" : \"粗略\"));\n}\n\n\n/**\n * @brief 修改 或 补充 某个镜像站的换源链接，即修改 Source_t.url\n *\n * @example 见 os_ubuntu_resetsrc() 中对非 x86_64 架构源地址的修改\n */\nvoid\nchef_set_repoURL (Target_t *target, SourceProvider_t *provider, char *url)\n{\n  xy_cant_be_null (target);\n  xy_cant_be_null (provider);\n  xy_cant_be_null (url);\n\n  for (int i=0; i < target->sources_n; i++)\n    {\n      Source_t *src = &target->sources[i];\n      SourceProvider_t *p = src->provider;\n      if (p == provider)\n        {\n          src->url = xy_strdup (url);\n          return;\n        }\n    }\n\n  xy_unreached();\n}\n\n\n/**\n * @brief 提供一个函数，这个函数基于 \"换源链接\" 和用户提供的数据来构造和填充精准测速链接\n */\nvoid\nchef_set_smURL_with_func (\n  Target_t *target,\n  SourceProvider_t *provider,\n  char *(*func)(const char *url, const char *user_data),\n  char *user_data)\n{\n  xy_cant_be_null (target);\n  xy_cant_be_null (provider);\n  xy_cant_be_null (func);\n\n  for (int i=0; i < target->sources_n; i++)\n    {\n      Source_t *src = &target->sources[i];\n      SourceProvider_t *p = src->provider;\n      if (p == provider)\n        {\n          if (src->url)\n            {\n              src->speed_measure_url = func (src->url, user_data);\n              return;\n            }\n          else\n            {\n              chsrc_panic (\"该函数基于已有的换源链接来生成测速链接，但该源的换源链接为空\");\n            }\n        }\n    }\n\n  xy_unreached();\n}\n\n\n/**\n * @brief 给 \"换源链接\" 增加一个后缀来构造和填充专用测速链接\n */\nvoid\nchef_set_smURL_with_postfix (Target_t *target, SourceProvider_t *provider, char *postfix)\n{\n  chef_set_smURL_with_func (target, provider, xy_2strcat, postfix);\n}\n\n\n/**\n * @internal 该函数仅用于实现 chef_set_smURL()\n */\nchar *\n_chef_strdup_2nd_argument (const char *DUMMY, const char *str)\n{\n  return xy_strdup (str);\n}\n\n/**\n * @breif 设置 或 修改 某个镜像站的 *精准*测速链接，即修改 Source_t.speed_measure_url\n */\nvoid\nchef_set_smURL (Target_t *target, SourceProvider_t *provider, char *url)\n{\n  chef_set_smURL_with_func (target, provider, _chef_strdup_2nd_argument, url);\n}\n\n\n/**\n * @brief 针对每一个剩下的还未设置专用测速链接的源，对其 \"换源链接\" 使用函数 `func` 来生成专用测速链接\n */\nvoid\nchef_set_rest_smURL_with_func (\n  Target_t *target,\n  char *(*func)(const char *url, const char *user_data),\n  char *user_data)\n{\n  xy_cant_be_null (target);\n\n  Source_t *sources = target->sources;\n  int n = target->sources_n;\n\n  for (int i=0; i<n; i++)\n    {\n      Source_t *src = &sources[i];\n      ProviderType_t type = src->provider->type;\n      if (src->url)\n        {\n          /* 为空时才修改 或者里面是脏数据 */\n          if (NULL==src->speed_measure_url || !hp_is_url (src->speed_measure_url))\n            {\n              src->speed_measure_url = func (src->url, user_data);\n            }\n        }\n    }\n}\n\n\n/**\n * @brief 针对每一个剩下的还未设置专用测速链接的源，对其 \"换源链接\" 增加一个后缀来生成专用测速链接\n */\nvoid\nchef_set_rest_smURL_with_postfix (Target_t *target, char *postfix)\n{\n  chef_set_rest_smURL_with_func (target, xy_2strcat, postfix);\n}\n\n\n/**\n * @note 用于: 组中的 item target 在 standalone 模式时正确填充源信息\n */\nvoid\nchef_use_other_target_sources (Target_t *this, Target_t *other)\n{\n  if (!other->inited)\n    {\n      if (other->preludefn)\n        other->preludefn();\n      else\n        {\n          chef_debug_target (other);\n          chsrc_panic (\"`other` 未定义 _prelude() !\");\n        }\n    }\n\n  this->sources = other->sources;\n  this->sources_n = other->sources_n;\n}\n\n\nvoid\nchef_allow_english (Target_t *target)\n{\n  xy_cant_be_null (target);\n  target->can_english = true;\n}\n\nvoid\nchef_deny_english (Target_t *target)\n{\n  xy_cant_be_null (target);\n  target->can_english = false;\n}\n\n\n/**\n * @brief 设置该 target 的作用域能力\n */\nvoid\nchef_set_scope_cap (Target_t *target, Scope_t scope, ScopeCapability_t cap)\n{\n  xy_cant_be_null (target);\n\n  /* 我们在这里固定好索引的位置，而不是直接用 enum 的值，防止以后顺序或者新增枚举值 */\n  if (scope == ProjectScope)\n    {\n      target->scope_caps[ScopeCap_Slot_Project] = cap;\n    }\n  else if (scope == UserScope)\n    {\n      target->scope_caps[ScopeCap_Slot_User] = cap;\n    }\n  else if (scope == SystemScope)\n    {\n      target->scope_caps[ScopeCap_Slot_System] = cap;\n    }\n  else\n    {\n      chsrc_panic (\"无效的 scope 参数\");\n    }\n}\n\n\n/**\n * @brief 设置该 target 的默认作用域\n *\n * @note 该函数必须在 chef_set_scope_cap() 之后调用，以确保默认作用域的能力已经被明确了\n */\nvoid\nchef_set_default_scope (Target_t *target, Scope_t scope)\n{\n  xy_cant_be_null (target);\n  target->default_scope = scope;\n\n  ScopeCapability_t cap = ScopeCap_Unknown;\n\n  if (scope == ProjectScope)\n    cap = target->scope_caps[ScopeCap_Slot_Project];\n  else if (scope == UserScope)\n    cap = target->scope_caps[ScopeCap_Slot_User];\n  else if (scope == SystemScope)\n    cap = target->scope_caps[ScopeCap_Slot_System];\n  else if (scope == ImplementationDefinedScope)\n    {\n      /* ImplementationDefinedScope 即由 chsrc 根据实际情况来决定，因此我们不对它检查 */\n      return;\n    }\n  else\n    {\n      chsrc_panic (\"无效的 scope 参数\");\n    }\n\n  /* 防止 chef 们写错 */\n  if (cap != ScopeCap_Able_And_Implemented)\n    {\n      chsrc_panic (\"该作用域未被明确支持，无法设置为默认作用域\");\n    }\n}\n\n\n/**\n * @brief 由于操作系统相关的 target 换源都是系统级，所以 scope 都是固定的，我们提供此快捷函数来设置\n */\nvoid\nchef_set_os_scope (Target_t *target)\n{\n  xy_cant_be_null (target);\n\n  chef_set_scope_cap (target, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (target, UserScope,    ScopeCap_Unable);\n  chef_set_scope_cap (target, SystemScope,  ScopeCap_Able_And_Implemented);\n\n  chef_set_default_scope (target, SystemScope);\n}\n\n\n\nvoid\nchef_allow_user_define (Target_t *target)\n{\n  xy_cant_be_null (target);\n\n  target->can_user_define = true;\n  target->can_user_define_explain = NULL;\n}\n\nvoid\nchef_deny_user_define (Target_t *target)\n{\n  xy_cant_be_null (target);\n\n  target->can_user_define = false;\n\n  char *reason = CHINESE ? \"URL将会根据内部实现重写,因此不能自定义\"\n                         : \"The URL will be rewritten based on internal implementation, so it cannot be customized\";\n  target->can_user_define_explain = reason;\n}\n\n\nvoid\nchef_set_note (Target_t *target, const char *note_zh, const char *note_en)\n{\n  xy_cant_be_null (target);\n\n  const char *msg = CHINESE ? note_zh : note_en;\n\n  if (msg)\n    target->note = xy_strdup (msg);\n}\n\n\n\n/**\n * @brief 验证该 `id` 所指的贡献者确有其人\n */\nContributor_t *\nchef_verify_contributor (const char *id)\n{\n  xy_cant_be_null (id);\n\n  Contributor_t *c = xy_map_get (ProgStore.contributors, id);\n  if (!c)\n    {\n      char error[256];\n      snprintf (error, sizeof (error), \"贡献者 %s 不存在, 是否写错？或请在 chsrc-main.c 中登记该贡献者\", id);\n      chsrc_panic (error);\n    }\n  return c;\n}\n\n\n/**\n * @brief 设置 Chef (recipe 负责人)\n */\nvoid\nchef_set_chef (Target_t *target, const char *id)\n{\n  xy_cant_be_null (target);\n\n  /* Chef 可为空 */\n  if (!id)\n    {\n      target->chef = NULL;\n      return;\n    }\n\n  Contributor_t *c = chef_verify_contributor (id);\n  target->chef = c;\n}\n\n\n/**\n * @brief 设置 Cooks (recipe 核心作者)\n */\nvoid\nchef_set_cooks (Target_t *target, size_t count, ...)\n{\n  xy_cant_be_null (target);\n\n  if (count == 0)\n    {\n      chsrc_panic (\"recipe 一定至少有1位作者(cooks)\");\n      return;\n    }\n\n  va_list args;\n  va_start (args, count);\n\n  target->cooks = xy_malloc0 (count * sizeof (Contributor_t*));\n  target->cooks_n = count;\n\n  for (size_t i = 0; i < count; i++)\n    {\n      char *id = va_arg (args, char*);\n      target->cooks[i] = chef_verify_contributor (id);\n    }\n\n  va_end (args);\n}\n\nvoid\nchef_set_sauciers (Target_t *target, uint32_t count, ...)\n{\n  xy_cant_be_null (target);\n\n  if (count == 0)\n    {\n      target->sauciers = NULL;\n      target->sauciers_n = 0;\n      return;\n    }\n\n  va_list args;\n  va_start (args, count);\n\n  target->sauciers = xy_malloc0 (count * sizeof (Contributor_t*));\n  target->sauciers_n = count;\n\n  for (uint32_t i = 0; i < count; i++)\n    {\n      char *id = va_arg (args, char*);\n      target->sauciers[i] = chef_verify_contributor (id);\n    }\n}\n\n\n\nvoid\nchef_set_recipe_created_on (Target_t *target, char *date)\n{\n  xy_cant_be_null (target);\n  xy_cant_be_null (date);\n\n  target->created_on = xy_strdup (date);\n}\n\n\nvoid\nchef_set_recipe_last_updated (Target_t *target, char *date)\n{\n  xy_cant_be_null (target);\n  xy_cant_be_null (date);\n\n  target->last_updated = xy_strdup (date);\n}\n\n\nvoid\nchef_set_sources_last_updated (Target_t *target, char *date)\n{\n  xy_cant_be_null (target);\n  xy_cant_be_null (date);\n\n  target->sources_last_updated = xy_strdup (date);\n}\n\n\n/**\n * @note 某些 target 需要修改 User-Agent\n * 由于单独测速 (chsrc measure) 的时候也需要进行此项修改，\n * 所以该函数不能仅仅放在 _setsrc() 里，而是应当放在 _prelude() 里\n */\nvoid\nchef_set_user_agent (char *user_agent)\n{\n  ProgStatus.user_agent = user_agent;\n}\n"
  },
  {
    "path": "src/framework/core.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Name     : core.c\n * File Authors  : @ccmywish\n *               | @G_I_Y\n * Contributors  : @Gn3po4g\n *               | @happy-game\n *               | @Yangmoooo\n *               | @BingChunMoLi\n *               | @Mikachu2333\n *               |\n * Created On    : <2023-08-29>\n * Last Modified : <2026-02-24>\n *\n * chsrc framework\n * ------------------------------------------------------------*/\n\n#if defined(__STDC__) && __STDC_VERSION__ < 201112L\n#   error \"chsrc requires C11 or later, please use a new compiler which at least supports C11\"\n#endif\n\n#if defined(__STDC__) && __STDC_VERSION__ < 201710L\n#   warning \"chsrc recommends a C17 or later compiler\"\n#endif\n\n#include \"xy.h\"\n#include \"struct.h\"\n#include \"mirror.c\"\n#include \"helper.c\"\n\n#define App_Name \"chsrc\"\n\nstatic int chsrc_get_cpucore ();\n\n\n/* Global Program Mode */\nstruct\n{\n  // 用户命令\n  bool MeasureMode;\n  bool ResetMode;\n\n  // 内部实现\n  bool TargetGroupMode;\n\n  // 用户命令选项\n  bool Ipv6Mode;\n  Scope_t Scope;\n  bool EnglishMode;\n  bool DryRunMode;\n  bool NoColorMode;\n}\nProgMode =\n{\n  .MeasureMode = false,\n  .ResetMode   = false,\n  .TargetGroupMode = false,\n  .Ipv6Mode = false,\n  .Scope = ImplementationDefinedScope,\n  .EnglishMode = false,\n  .DryRunMode = false,\n  .NoColorMode = false\n};\n\n/* recipe 相关 mode */\nbool chsrc_in_target_group_mode() {return ProgMode.TargetGroupMode;}\n// 并非作为 follower target，而是自身作为一个独立的 target 执行\nbool chsrc_in_standalone_mode() {return !ProgMode.TargetGroupMode;}\nvoid chsrc_set_target_group_mode(){ProgMode.TargetGroupMode = true;}\n\nbool chsrc_in_reset_mode(){return ProgMode.ResetMode;}\n/* 默认换源作用域就是 ImplementationDefinedScope */\nbool chsrc_in_default_scope_mode(){return ProgMode.Scope == ImplementationDefinedScope;}\nbool chsrc_in_user_scope_mode(){return ProgMode.Scope == UserScope;}\nbool chsrc_in_project_scope_mode(){return ProgMode.Scope == ProjectScope;}\nbool chsrc_in_system_scope_mode(){return ProgMode.Scope == SystemScope;}\n\nbool chsrc_in_english_mode(){return ProgMode.EnglishMode;}\nbool chsrc_in_no_color_mode(){return ProgMode.NoColorMode;}\n\n/* Convenience */\n#define ENGLISH chsrc_in_english_mode()\n#define CHINESE !chsrc_in_english_mode()\n\n/* 仅 framework 相关 mode */\nstatic bool in_measure_mode(){return ProgMode.MeasureMode;}\nstatic bool in_ipv6_mode(){return ProgMode.Ipv6Mode;}\nstatic bool in_dry_run_mode(){return ProgMode.DryRunMode;}\n\n\n/**\n * Target Group mode (相反则称为 standalone mode)\n *\n *   1. 一个 target group 包含了多个 target，这些都被叫做 follower target\n *   2. 触发该运行模式的 target 被称为 leader target，其往往只是一个virtual target，类似 APT 中的 virtual package\n *\n * 目前使用该模式的有两个: Python 和 Node.js，因为二者的包管理器存在多个\n */\n\n\ntypedef enum ChgType_t\n{\n  ChgType_Auto,\n  ChgType_Reset,\n  ChgType_SemiAuto,\n  ChgType_Manual,\n  ChgType_Untested\n} ChgType_t;\n\n\n/* Global Program Status */\nstruct\n{\n  int leader_selected_index;   /* leader target 选中的索引 */\n  ChgType_t chgtype;           /* 换源实现的类型 */\n\n  /* 此时 chsrc_run() 不再是recipe中指定要运行的一个外部命令，而是作为一个功能实现的支撑 */\n  bool chsrc_run_faas;\n  char *user_agent;\n}\nProgStatus =\n{\n  .leader_selected_index = -1,\n  .chgtype = ChgType_Auto,\n  .chsrc_run_faas = false,\n  .user_agent = \"chsrc/\" Chsrc_Version,\n};\n\n\n/* Global Program Store */\nstruct\n{\n  XySeq_t *pl;\n  XySeq_t *os;\n  XySeq_t *wr;\n  XyMap_t *contributors; /* 所有贡献者 */\n}\nProgStore =\n{\n  .pl = NULL,\n  .os = NULL,\n  .wr = NULL,\n  .contributors = NULL,\n};\n\n\n\n#define Exit_OK               0\n#define Exit_Fatal            1\n#define Exit_Unknown          2\n#define Exit_Unsupported      3\n#define Exit_UserCause        4\n#define Exit_MaintainerCause  5\n#define Exit_ExternalError    6\n\n#define chsrc_log(str)     xy_log(App_Name,str)\n#define chsrc_succ(str)    xy_succ(App_Name,str)\n#define chsrc_info(str)    xy_info(App_Name,str)\n#define chsrc_warn(str)    xy_warn(App_Name,str)\n#define chsrc_error(str)   xy_error(App_Name,str)\n#ifdef XY_DEBUG\n  #define chsrc_debug(dom,str) xy_warn(App_Name \"(DEBUG \" dom \")\",str)\n#else\n  #define chsrc_debug(dom,str)\n#endif\n#define chsrc_verbose(str) xy_info(App_Name \"(VERBOSE)\",str)\n#define chsrc_panic(reason) xy_error(App_Name \"(PANIC)\",reason); exit(Exit_MaintainerCause)\n\n#define faint(str)    xy_str_to_faint(str)\n#define red(str)      xy_str_to_red(str)\n#define blue(str)     xy_str_to_blue(str)\n#define green(str)    xy_str_to_green(str)\n#define yellow(str)   xy_str_to_yellow(str)\n#define purple(str)   xy_str_to_purple(str)\n#define bold(str)     xy_str_to_bold(str)\n#define bdred(str)    xy_str_to_bold(xy_str_to_red(str))\n#define bdblue(str)   xy_str_to_bold(xy_str_to_blue(str))\n#define bdgreen(str)  xy_str_to_bold(xy_str_to_green(str))\n#define bdyellow(str) xy_str_to_bold(xy_str_to_yellow(str))\n#define bdpurple(str) xy_str_to_bold(xy_str_to_purple(str))\n\n/* 2系列都是带有括号的 */\n#define chsrc_succ2(str)    xy_succ_brkt(App_Name,ENGLISH?\"SUCCEED\":\"成功\",str)\n#define chsrc_log2(str)     xy_info_brkt(App_Name,\"LOG\",str)\n#define chsrc_warn2(str)    xy_warn_brkt(App_Name,ENGLISH?\"WARN\":\"警告\",str)\n#define chsrc_error2(str)   xy_error_brkt(App_Name,ENGLISH?\"ERROR\":\"错误\",str)\n#ifdef XY_DEBUG\n  #define chsrc_debug2(dom,str) xy_warn_brkt(App_Name,\"DEBUG \" dom,str)\n#else\n  #define chsrc_debug2(dom,str)\n#endif\n#define chsrc_verbose2(str) xy_info_brkt(App_Name,\"VERBOSE\",str)\n\n/**\n * @note 输出在 stdout 中\n */\nvoid\nchsrc_note2 (const char *str)\n{\n  char *msg = ENGLISH ? \"NOTE\" : \"提示\";\n  xy_log_brkt (blue(App_Name), bdblue(msg), blue(str));\n}\n\n/**\n * @note 输出在 stdout 中\n */\nvoid\nchsrc_alert2 (const char *str)\n{\n  char *msg = ENGLISH ? \"ALERT\" : \"提醒\";\n  xy_log_brkt (yellow(App_Name), bdyellow(msg), yellow(str));\n}\n\n\n\nvoid\nchsrc_init_framework ()\n{\n  xy_init ();\n\n  ProgStore.contributors = xy_map_new ();\n  ProgStore.pl = xy_seq_new ();\n  ProgStore.os = xy_seq_new ();\n  ProgStore.wr = xy_seq_new ();\n}\n\n\n\nvoid\nchsrc_log_write (const char *filename, bool is_overwrite)\n{\n  char *msg = is_overwrite ? (ENGLISH ? \"OVERWRITE\" : \"覆写\") : (ENGLISH ? \"WRITE\" : \"写入\");\n\n  xy_log_brkt (blue(App_Name), bdblue(msg), blue(filename));\n}\n\nvoid\nchsrc_log_backup (const char *filename)\n{\n  char *msg = ENGLISH ? \"BACKUP\" : \"备份\";\n\n  char *bak = xy_2strcat (filename, \".bak\");\n  xy_log_brkt (blue(App_Name), bdblue(msg), xy_strcat (3, bdyellow(filename), \" -> \", bdgreen(bak)));\n}\n\n#define YesMark \"✓\"\n#define NoMark \"x\"\n#define HalfYesMark \"⍻\"\n\n\nstatic void\nlog_check_result (const char *check_what, const char *check_type, bool exist)\n{\n  char *chk_msg       = NULL;\n  char *not_exist_msg = NULL;\n  char *exist_msg     = NULL;\n\n  if (ENGLISH)\n    {\n      chk_msg       = \"CHECK\";\n      not_exist_msg = \" doesn't exist\";\n      exist_msg     = \" exists\";\n    }\n  else\n    {\n      chk_msg       = \"检查\";\n      not_exist_msg = \" 不存在\";\n      exist_msg     = \" 存在\";\n    }\n\n\n  if (!exist)\n    {\n      xy_log_brkt (App_Name, bdred (chk_msg), xy_strcat (5,\n                   red (NoMark \" \"), check_type, \" \", red (check_what), not_exist_msg));\n    }\n  else\n    {\n      xy_log_brkt (App_Name, bdgreen (chk_msg), xy_strcat (5,\n                   green (YesMark \" \"), check_type, \" \", green (check_what), exist_msg));\n    }\n}\n\n\nstatic void\nlog_cmd_result (bool result, int exit_status, bool use_yellow_for_error)\n{\n  char *run_msg  = NULL;\n  char *succ_msg = NULL;\n  char *fail_msg = NULL;\n\n  if (ENGLISH)\n    {\n      run_msg  = \"RUN\";\n      succ_msg = YesMark \" executed successfully\";\n      fail_msg = NoMark  \" executed unsuccessfully, exit status: \";\n    }\n  else\n    {\n      run_msg  = \"运行\";\n      succ_msg = YesMark \" 命令执行成功\";\n      fail_msg = NoMark  \" 命令执行失败，退出状态: \";\n    }\n\n  if (result)\n    xy_log_brkt (green (App_Name), bdgreen (run_msg), green (succ_msg));\n  else\n    {\n      char buf[8] = {0};\n      sprintf (buf, \"%d\", exit_status);\n\n      if (use_yellow_for_error)\n        {\n          char *log = xy_2strcat (yellow (fail_msg), bdyellow (buf));\n          xy_log_brkt (yellow (App_Name), bdyellow (run_msg), log);\n        }\n      else\n        {\n          char *log = xy_2strcat (red (fail_msg), bdred (buf));\n          xy_log_brkt (red (App_Name), bdred (run_msg), log);\n        }\n    }\n}\n\n\n\n#define Quiet_When_Exist    0x00\n#define Noisy_When_Exist    0x01\n#define Quiet_When_NonExist 0x00\n#define Noisy_When_NonExist 0x10\n\n/**\n * 检测二进制程序是否存在\n *\n * @param  check_cmd  检测 `prog_name` 是否存在的一段命令，一般来说，填 `prog_name` 本身即可，\n *                    但是某些情况下，需要使用其他命令绕过一些特殊情况，比如 python 这个命令在Windows上\n *                    会自动打开 Microsoft Store，需避免\n *\n * @param  prog_name  要检测的二进制程序名\n *\n */\nbool\nquery_program_exist (char *check_cmd, char *prog_name, int mode)\n{\n  char *which = check_cmd;\n\n  int status = system (which);\n\n  // char buf[32] = {0}; sprintf(buf, \"错误码: %d\", status);\n\n  char *msg = ENGLISH ? \"command\" : \"命令\";\n\n  if (0 != status)\n    {\n      if (mode & Noisy_When_NonExist)\n        {\n          // xy_warn (xy_strcat(4, \"× 命令 \", progname, \" 不存在，\", buf));\n          log_check_result (prog_name, msg, false);\n        }\n      return false;\n    }\n  else\n    {\n      if (mode & Noisy_When_Exist)\n        log_check_result (prog_name, msg, true);\n      return true;\n    }\n}\n\n\n/**\n * @brief 生成用于 “检测一个程序是否存在” 的命令，该内部函数由 chsrc_check_program() 家族调用\n *\n * @note\n *   1. Unix 中，'where' 命令仅在 Zsh 中可以使用，sh 和 Bash 中均无法使用，因为其并非二进制程序\n *   2. 因部分 Linux 发行版中没有 'which' 和 'whereis' 命令，使用 'command -v' 代替\n */\nstatic char *\ncmd_to_check_program (char *prog_name)\n{\n  char *check_tool = xy.on_windows ?  \"where \" : \"command -v \";\n\n  char *quiet_cmd = xy_quiet_cmd (xy_2strcat (check_tool, prog_name));\n\n  return quiet_cmd;\n}\n\n\n/**\n * @brief 通过 `调用程序名 --version` 的方式检测程序是否存在\n *\n * @deprecated 因存在以下三个问题弃用：\n *\n *  1. 该程序得到直接执行，可能不太安全 (虽然基本不可能)\n *  2. 有一些程序启动速度太慢，即使只调用 --version，也依旧会花费许多时间，比如 mvn\n *  3. 有些程序并不支持 --version 选项 (虽然基本不可能)\n */\nXY_Deprecate_This(\"Use cmd_to_check_program() instead\")\nstatic char *\ncmd_to_check_program2 (char *prog_name)\n{\n  char *quiet_cmd = xy_quiet_cmd (xy_2strcat (prog_name, \" --version\"));\n  return quiet_cmd;\n}\n\n\n/**\n * @brief 检测程序是否存在\n *\n * @note\n *  1. 一般只在 recipe 中使用，显式检测每一个需要用到的 program\n *  2. 无论存在与否，*均输出检测信息*\n *\n */\nbool\nchsrc_check_program (char *prog_name)\n{\n  return query_program_exist (cmd_to_check_program(prog_name), prog_name, Noisy_When_Exist|Noisy_When_NonExist);\n}\n\n/**\n * @brief 检测程序是否存在\n *\n * @note\n *  1. 此函数没有强制性，只返回检查结果\n *  2. 无论存在与否，*均不输出检测信息*\n */\nbool\nchsrc_check_program_quietly (char *prog_name)\n{\n  return query_program_exist (cmd_to_check_program(prog_name), prog_name, Quiet_When_Exist|Quiet_When_NonExist);\n}\n\n/**\n * @brief 检测程序是否存在\n *\n * @note 存在时不输出检测信息，不存在时才输出检测信息\n *\n */\nbool\nchsrc_check_program_quietly_when_exist (char *prog_name)\n{\n  return query_program_exist (cmd_to_check_program(prog_name), prog_name, Quiet_When_Exist|Noisy_When_NonExist);\n}\n\n\n/**\n * @brief 确保程序一定存在\n *\n * @note\n *  1. 此函数具有强制性，检测不到就直接退出\n *  2. 存在时不输出检测信息，不存在时才输出检测信息\n *\n */\nvoid\nchsrc_ensure_program (char *prog_name)\n{\n  bool exist = query_program_exist (cmd_to_check_program(prog_name), prog_name, Quiet_When_Exist|Noisy_When_NonExist);\n  if (exist)\n    {\n      // OK, nothing should be done\n    }\n  else\n    {\n      char *msg1 = ENGLISH ? \"not found \" : \"未找到 \";\n      char *msg2 = ENGLISH ? \" command, please check for existence\" : \" 命令，请检查是否存在\";\n      chsrc_error (xy_strcat (3, msg1, prog_name, msg2));\n      exit (Exit_UserCause);\n    }\n}\n\n\nbool\nchsrc_check_file (char *path)\n{\n  char *msg = ENGLISH ? \"file\" : \"文件\";\n  if (xy_file_exist (path))\n    {\n      log_check_result (path, msg, true);\n      return true;\n    }\n  else\n    {\n      log_check_result (path, msg, false);\n      return false;\n    }\n}\n\n\n/**\n * 用于 _setsrc 函数，检测用户输入的镜像站code，是否存在于该target可用源中\n *\n * @note 一个源Source必定来自于一个Provider，所以该函数名叫 query_mirror_exist\n *\n * @param  target_name  目标名\n * @param  input        如果用户输入 default 或者 def，则选择第一个源\n */\nint\nquery_mirror_exist (Source_t *sources, size_t size, char *target_name, char *input)\n{\n  if (hp_is_url (input))\n    {\n      char *msg = ENGLISH ? \"Using user-defined sources for this software is not supported at this time, please contact the developers to ask why or request support\" : \"暂不支持对该软件使用用户自定义源，请联系开发者询问原因或请求支持\";\n      chsrc_error (msg);\n      exit (Exit_Unsupported);\n    }\n\n  if (0==size)\n    {\n      char *msg1 = ENGLISH ? \"Currently \" : \"当前 \";\n      char *msg2 = ENGLISH ? \" doesn't have any source available. Please contact the maintainers\" : \" 无任何可用源，请联系维护者\";\n      chsrc_error (xy_strcat (3, msg1, target_name, msg2));\n      exit (Exit_MaintainerCause);\n    }\n\n  if (1==size)\n    {\n      char *msg1 = ENGLISH ? \"Currently \" : \"当前 \";\n      char *msg2 = ENGLISH ? \" only the upstream source exists. Please contact the maintainers\" : \" 仅存在上游默认源，请联系维护者\";\n      chsrc_error (xy_strcat (3, msg1, target_name, msg2));\n      exit (Exit_MaintainerCause);\n    }\n\n  /* if (xy_streql (\"reset\", input)) 不再使用这种方式 */\n  if (chsrc_in_reset_mode())\n    {\n      char *msg = ENGLISH ? \"Will reset to the upstream's default source\" : \"将重置为上游默认源\";\n      say (msg);\n      return 0; /* 返回第1个，因为第1个是上游默认源 */\n    }\n\n  if (2==size)\n    {\n      char *msg1 = ENGLISH ? \" is \" : \" 是 \";\n      char *msg2 = ENGLISH ? \"'s ONLY mirror available currently, thanks for their generous support\"\n                           : \" 目前唯一可用镜像站，感谢他们的慷慨支持\";\n      const char *name = ENGLISH ? sources[1].mirror->abbr\n                                 : sources[1].mirror->name;\n      chsrc_succ (xy_strcat (4, name, msg1, target_name, msg2));\n    }\n\n  if (xy_streql (\"first\", input))\n    {\n      char *msg = ENGLISH ? \"Will use the first speedy source measured by maintainers\" : \"将使用维护团队测速第一的源\";\n      say (msg);\n      return 1; /* 返回第2个，因为第1个是上游默认源 */\n    }\n\n  int idx = 0;\n  Source_t src = sources[0];\n\n  bool exist = false;\n  for (int i=0; i<size; i++)\n    {\n      src = sources[i];\n      if (xy_streql (src.mirror->code, input))\n        {\n          idx = i;\n          exist = true;\n          break;\n        }\n    }\n  if (!exist)\n    {\n      {\n        char *msg1 = ENGLISH ? \"Mirror site \"   : \"镜像站 \";\n        char *msg2 = ENGLISH ? \" doesn't exist\" : \" 不存在\";\n        chsrc_error (xy_strcat (3, msg1, input, msg2));\n      }\n\n      char *msg = ENGLISH ? \"To see available sources, use chsrc list \" : \"查看可使用源，请使用 chsrc list \";\n      chsrc_error (xy_2strcat (msg, target_name));\n      exit (Exit_UserCause);\n    }\n  return idx;\n}\n\n\n/**\n * 该函数来自 oh-my-mirrorz.py，由 @ccmywish 翻译为C语言，但功劳和版权属于原作者\n *\n * @param speed 单位为Byte/s\n */\nchar *\nto_human_readable_speed (double speed)\n{\n  char *scale[] = {\"Byte/s\", \"KByte/s\", \"MByte/s\", \"GByte/s\", \"TByte/s\"};\n  int i = 0;\n  while (speed > 1024.0)\n  {\n    i += 1;\n    speed /= 1024.0;\n  }\n  char *buf = xy_malloc0 (64);\n  sprintf (buf, \"%.2f %s\", speed, scale[i]);\n\n  char *new = NULL;\n  if (i <= 1 ) new = red (buf);\n  else\n    {\n      if (i == 2 && speed < 2.00) new = yellow (buf);\n      else new = green (buf);\n    }\n  return new;\n}\n\n\n/**\n * 测速代码参考自 https://github.com/mirrorz-org/oh-my-mirrorz/blob/master/oh-my-mirrorz.py\n * 功劳和版权属于原作者，由 @ccmywish 修改为C语言，并做了额外调整\n *\n * @return 返回测得的速度，若出错，返回-1\n *\n * 该函数实际原型为 char * (*)(const char*)\n */\nvoid *\nmeasure_speed_for_url (void *url)\n{\n  char *time_sec = NULL;\n\n  time_sec = \"8\";\n\n  /**\n   * 现在我们切换至跳转后的链接来测速，不再使用下述判断\n   *\n   * if (xy_str_start_with(url, \"https://registry.npmmirror\"))\n   *   {\n   *     // 这里 npmmirror 跳转非常慢，需要1~3秒，所以我们给它留够至少8秒测速时间，否则非常不准\n   *     time_sec = \"10\";\n   *   }\n   */\n\n  char *ipv6 = \"\"; // 默认不启用\n\n  if (in_ipv6_mode())\n    {\n      ipv6 = \"--ipv6\";\n    }\n\n  char *os_devnull = xy.os_devnull;\n\n  /**\n   * @note 我们用 —L，因为部分链接会跳转到其他地方，比如: RubyChina, npmmirror\n   */\n  char *curl_cmd = xy_strcat (10, \"curl -qsL \", ipv6,\n                                    \" -o \", os_devnull,\n                                    \" -w \\\"%{http_code} %{speed_download}\\\" -m\", time_sec,\n                                    \" -A \", ProgStatus.user_agent, \" \", url);\n\n  // chsrc_note2 (xy_2strcat (\"测速命令 \", curl_cmd));\n  char *curl_buf = xy_run (curl_cmd, 0);\n  return curl_buf;\n}\n\n\n/**\n * @return 返回速度speed，单位为 Byte/s\n */\ndouble\nparse_and_say_curl_result (char *curl_buf)\n{\n  // 分隔两部分数据\n  char *split = strchr (curl_buf, ' ');\n  if (split) *split = '\\0';\n\n  // say(curl_buf); say(split+1);\n     int http_code = atoi (curl_buf);\n  double     speed = atof (split+1);\n    char *speedstr = to_human_readable_speed (speed);\n\n  if (200!=http_code)\n    {\n      char *http_code_str = yellow (xy_2strcat (\"HTTP码 \", curl_buf));\n      say (xy_strcat (3, speedstr, \" | \",  http_code_str));\n    }\n  else\n    {\n      say (speedstr);\n    }\n  return speed;\n}\n\n\nint\nget_max_ele_idx_in_dbl_ary (double *array, int size)\n{\n  double maxval = array[0];\n  int maxidx = 0;\n\n  for (int i=1; i<size; i++)\n    {\n      if (array[i]>maxval)\n        {\n          maxval = array[i];\n          maxidx = i;\n        }\n    }\n  return maxidx;\n}\n\n\n/**\n * @param      sources        所有待测源\n * @param      size           待测源的数量\n * @param[out] speed_records  速度值记录，单位为Byte/s\n */\nvoid\nmeasure_speed_for_every_source (Source_t sources[], int size, double speed_records[])\n{\n  // bool get_measured[size]; /* 是否真正执行了测速 */\n  int get_measured_n = 0;     /* 测速了几个        */\n  char *measure_msgs[size];\n\n  double speed = 0.0;\n\n  for (int i=0; i<size; i++)\n    {\n      Source_t src = sources[i];\n\n      SourceProvider_t *provider = src.provider;\n      ProviderSpeedMeasureInfo_t psmi = provider->psmi;\n\n      bool provider_skip = psmi.skip;\n\n      bool has_dedicated_speed_url = false;\n\n      /**\n       * 存在两类测速链接\n       * 1. 有*专用测速链接*时，我们选专用，这是精准测速\n       * 2. 若无，我们用*镜像站整体测速链接*来进行代替，\n       *      若是专用镜像站，则是精准测速\n       *      若是通用镜像站，则是模糊测速\n       */\n      const char *provider_speed_url = psmi.url;\n      const char *dedicated_speed_url = src.speed_measure_url;\n\n      /* 最终用来测速的 URL */\n      char *url = NULL;\n\n      if (!provider_skip && !provider_speed_url)\n      /* 没有声明跳过，但是却没有提供 URL，这是维护者维护时出了纰漏，我们软处理 */\n        {\n          char *msg1 = ENGLISH ? \"Maintainers don't offer \" : \"维护者未提供 \";\n          char *msg2 = ENGLISH ? \" mirror site's speed measure link, so skip it\" : \" 镜像站测速链接，跳过该站点（需修复）\";\n          chsrc_warn (xy_strcat (3, msg1, provider->code, msg2));\n          speed = 0;\n\n          speed_records[i] = speed;\n          // get_measured[i] = false;\n          measure_msgs[i] = NULL;\n        }\n      else if (!provider_skip && provider_speed_url)\n        {\n          if (hp_is_url (provider_speed_url))\n            {\n              url = xy_strdup (provider_speed_url);\n              chsrc_debug (\"m\", xy_2strcat (\"使用镜像站整体测速链接: \", url));\n            }\n        }\n      else if (provider_skip)\n        {\n          /* Provider 被声明为跳过测速，下方判断精准测速链接有无提供，若也没有提供，将会输出跳过原因  */\n        }\n\n      if (dedicated_speed_url)\n        {\n          if (hp_is_url (dedicated_speed_url))\n            {\n              url = xy_strdup (dedicated_speed_url);\n              has_dedicated_speed_url = true;\n              chsrc_debug (\"m\", xy_2strcat (\"使用专用测速链接: \", url));\n            }\n          else\n            {\n              /* 防止维护者没填，这里有一些脏数据，我们软处理：假装该链接URL不存在 */\n              has_dedicated_speed_url = false;\n              chsrc_debug (\"m\", xy_2strcat (\"专用测速链接为脏数据，请修复: \", provider->name));\n            }\n        }\n\n\n      if (provider_skip && !has_dedicated_speed_url)\n        {\n          if (xy_streql (\"upstream\", provider->code))\n            {\n              /* 上游源不测速，但不置0，因为要避免这么一种情况: 可能其他镜像站测速都为0，最后反而选择了该 upstream */\n              speed = -1024*1024*1024;\n              if (!src.url)\n                {\n                  psmi.skip_reason_CN = \"缺乏对上游默认源进行测速的URL，请帮助补充\";\n                  psmi.skip_reason_EN = \"Lack of URL to measure upstream default source provider, please help to add\";\n                }\n            }\n          else if (xy_streql (\"user\", provider->code))\n            {\n              /* 代码不会执行至此 */\n              speed = 1024*1024*1024;\n            }\n          else\n            {\n              /* 不测速的 Provider */\n              speed = 0;\n            }\n          // get_measured[i] = false;\n          speed_records[i] = speed;\n\n          const char *msg = ENGLISH ? provider->abbr : provider->name;\n          const char *skip_reason = ENGLISH ? psmi.skip_reason_EN : psmi.skip_reason_CN;\n          if (NULL==skip_reason)\n            {\n              skip_reason = ENGLISH ? \"SKIP for no reason\" : \"无理由跳过\";\n            }\n          measure_msgs[i] = xy_strcat (4, faint(\"  x \"), msg, \" \", yellow(faint(skip_reason)));\n          println (measure_msgs[i]);\n\n          /* 下一位 */\n          continue;\n        }\n\n      /* 此时，一定获得了一个用于测速的链接 */\n      if (url)\n        {\n          const char *msg = ENGLISH ? provider->abbr : provider->name;\n\n          bool is_accurate = false;\n          if (has_dedicated_speed_url)\n            {\n              is_accurate = true;\n            }\n          else if (provider->psmi.accurate)\n            {\n              is_accurate = true;\n            }\n\n          char *accurate_msg = CHINESE ? (is_accurate ? bdblue(faint(\"[精准测速]\")) :  faint(\"[模糊测速]\"))\n                                       : (is_accurate ? bdblue(faint(\"[accurate]\")) : faint(\"[rough]\"));\n\n          if (xy_streql (\"upstream\", provider->code))\n            {\n              measure_msgs[i] = xy_strcat (7, faint(\"  ^ \"), msg, \" (\", src.url, \") \", accurate_msg, faint(\" ... \"));\n            }\n          else\n            {\n              measure_msgs[i] = xy_strcat (5, faint(\"  - \"), msg, \" \", accurate_msg, faint(\" ... \"));\n            }\n\n          print (measure_msgs[i]);\n          fflush (stdout);\n\n          char *curl_result = measure_speed_for_url (url);\n          double speed = parse_and_say_curl_result (curl_result);\n          speed_records[i] = speed;\n\n          /* 释放 url 内存 */\n          if (url) free (url);\n        }\n      else\n        {\n          xy_unreached();\n        }\n    }\n}\n\n\n\n/**\n * 自动测速选择镜像站和源\n */\nint\nauto_select_mirror (Source_t *sources, size_t size, const char *target_name)\n{\n  /* reset 时选择默认源 */\n  if (chsrc_in_reset_mode())\n    return 0;\n\n  if (!in_dry_run_mode())\n  {\n    char *msg = ENGLISH ? \"Measuring speed in sequence\" : \"测速中\";\n    xy_log_brkt (App_Name, bdpurple (ENGLISH ? \"MEASURE\" : \"测速\"), msg);\n    br();\n  }\n\n  if (0==size || 1==size)\n    {\n      char *msg1 = ENGLISH ? \"Currently \" : \"当前 \";\n      char *msg2 = ENGLISH ? \"No any source, please contact maintainers: chsrc issue\" : \" 无任何可用源，请联系维护者: chsrc issue\";\n      chsrc_error (xy_strcat (3, msg1, target_name, msg2));\n      exit (Exit_MaintainerCause);\n    }\n\n  if (in_dry_run_mode())\n  /* Dry Run 时，跳过测速 */\n    {\n      return 1; /* 原则第一个源 */\n    }\n\n  bool only_one = false;\n  if (2==size) only_one = true;\n\n  /** --------------------------------------------- */\n  bool exist_curl = chsrc_check_program_quietly_when_exist (\"curl\");\n  if (!exist_curl)\n    {\n      char *msg = ENGLISH ? \"No curl, unable to measure speed\" : \"没有curl命令，无法测速\";\n      chsrc_error (msg);\n      exit (Exit_UserCause);\n    }\n\n  if (xy.on_windows)\n    {\n      char *curl_version = xy_run (\"curl --version\", 1);\n      /**\n       * https://github.com/RubyMetric/chsrc/issues/144\n       *\n       * Cygwin上，curl 的版本信息为:\n       *\n       *    curl 8.9.1 (x86_64-pc-cygwin)\n       *\n       */\n      if (strstr (curl_version, \"pc-cygwin\"))\n        {\n          char *msg = ENGLISH ? \"You're using curl built by Cygwin which has a bug! Please use another curl!\" : \"你使用的是Cygwin构建的curl，该版本的curl存在bug，请改用其他版本的curl\";\n          chsrc_error (msg);\n          exit (Exit_UserCause);\n        }\n    }\n  /** --------------------------------------------- */\n\n  /* 总测速记录值 */\n  double speed_records[size];\n  measure_speed_for_every_source (sources, size, speed_records);\n  br();\n\n  /* DEBUG */\n  /*\n  for (int i=0; i<size; i++)\n    {\n      printf (\"speed_records[%d] = %f\\n\", i, speed_records[i]);\n    }\n  */\n\n  int fast_idx = get_max_ele_idx_in_dbl_ary (speed_records, size);\n\n  if (only_one)\n    {\n      char *msg1 = ENGLISH ? \"NOTICE  mirror site: \" : \"镜像站提示: \";\n      char   *is = ENGLISH ? \" is \" : \" 是 \";\n      char *msg2 = ENGLISH ? \"'s ONLY mirror available currently, thanks for their generous support\"\n                           : \" 目前唯一可用镜像站，感谢他们的慷慨支持\";\n      const char *name = ENGLISH ? sources[fast_idx].mirror->abbr\n                                 : sources[fast_idx].mirror->name;\n      say (xy_strcat (5, msg1, bdgreen(name), green(is), green(target_name), green(msg2)));\n    }\n  else\n    {\n      char *msg = ENGLISH ? \"FASTEST mirror site: \" : \"最快镜像站: \";\n      const char *name = ENGLISH ? sources[fast_idx].mirror->abbr\n                                 : sources[fast_idx].mirror->name;\n      say (xy_2strcat (msg, green(name)));\n    }\n\n  // https://github.com/RubyMetric/chsrc/pull/71\n  if (in_measure_mode())\n    {\n      char *msg = ENGLISH ? \"URL of above source: \" : \"镜像源地址: \";\n      say (xy_2strcat (msg, green(sources[fast_idx].url)));\n    }\n\n  return fast_idx;\n}\n\n\n\nint\nuse_specific_mirror_or_auto_select (char *input, Target_t *t)\n{\n  if (input)\n    {\n      return query_mirror_exist (t->sources, t->sources_n, t->aliases, input);\n    }\n  else\n    {\n      return auto_select_mirror (t->sources, t->sources_n, t->aliases);\n    }\n}\n\n\nbool\nsource_is_upstream (Source_t *source)\n{\n  return xy_streql (source->mirror->code, \"upstream\");\n}\n\nbool\nsource_is_userdefine (Source_t *source)\n{\n  return xy_streql (source->mirror->code, \"user\");\n}\n\nbool\nsource_has_empty_url (Source_t *source)\n{\n  return source->url == NULL;\n}\n\n\n\n/**\n * @brief 为该 target 确定最终将使用的源\n *\n * 用户*只可能*通过下面5种方式来换源，无论哪一种都会返回一个 Source_t 出来\n *\n *   1. 用户指定了一个 Mirror Code，即 chsrc set <target> <code>\n *   2. 用户指定了一个 URL，        即 chsrc set <target> https://ur\n *   3. 用户什么都没指定，          即 chsrc set <target>\n *   4. 用户正在重置源，            即 chsrc reset <target>\n *\n * 如果处于 Target Group 模式下，leader target 已经测速过了，follower target\n * 不能再次测速，而是直接选择 leader 测过的结果\n *\n *   5. leader target 测速出来的某个源\n *\n */\nSource_t\nchsrc_yield_source (Target_t *t, char *option)\n{\n  /**\n   * 防止某些意外时刻 _setsrc() 等函数会被直接调，但此时 _prelude() 还没有执行过\n   * 我们在这里卡一道，确保 _prelude() 被调用\n   *\n   * 目前可能出现这种情况的时候：组换源的时候，组成菜的 _setsrc() 被直接调用\n   */\n  if (!t->inited) t->preludefn();\n\n  Source_t source;\n  if (chsrc_in_target_group_mode() && ProgStatus.leader_selected_index==-1)\n    {\n      ProgStatus.leader_selected_index = use_specific_mirror_or_auto_select (option, t);\n      source = t->sources[ProgStatus.leader_selected_index];\n    }\n  else if (chsrc_in_target_group_mode() && ProgStatus.leader_selected_index!=-1)\n    {\n      source = t->sources[ProgStatus.leader_selected_index];\n    }\n  else if (hp_is_url (option))\n    {\n      Source_t tmp = { &UserDefinedProvider, option };\n      source = tmp;\n    }\n  else\n    {\n      int index = use_specific_mirror_or_auto_select (option, t);\n      source = t->sources[index];\n    }\n  return source;\n}\n\n\n\n\n#define hr() say (\"--------------------------------\");\n\n\n/**\n * 用于 _setsrc 函数\n *\n * 1. 告知用户选择了什么源和镜像\n * 2. 对选择的源和镜像站进行一定的校验\n */\nvoid\nchsrc_confirm_source (Source_t *source)\n{\n  // 由于实现问题，我们把本应该独立出去的上游默认源，也放在了可以换源的数组中，而且放在第一个\n  // chsrc 已经规避用户使用未实现的 `chsrc reset`\n  // 但是某些用户可能摸索着强行使用 chsrc set target upstream，从而执行起该禁用的功能，\n  // 之所以禁用，是因为有的 reset 我们并没有实现，我们在这里阻止这些邪恶的用户\n  if (source_is_upstream (source) && source_has_empty_url (source))\n    {\n      char *msg = ENGLISH ? \"Not implement `reset` for the target yet\" : \"暂未对该目标实现重置\";\n      chsrc_error (msg);\n      exit (Exit_Unsupported);\n    }\n  else if (source_has_empty_url (source))\n    {\n      char *msg = ENGLISH ? \"URL of the source doesn't exist, please report a bug to the dev team\" : \\\n                                     \"该源URL不存在，请向维护团队提交bug\";\n      chsrc_error (msg);\n      exit (Exit_MaintainerCause);\n    }\n  else\n    {\n      char *msg = ENGLISH ? \"SELECT  mirror site: \" : \"选中镜像站: \";\n      say (xy_strcat (5, msg, green (source->mirror->abbr), \" (\", green (source->mirror->code), \")\"));\n    }\n\n  hr();\n}\n\n\nSource_t\nchsrc_yield_source_and_confirm (Target_t *t, char *option)\n{\n  Source_t source = chsrc_yield_source(t, option);\n  chsrc_confirm_source(&source);\n  return source;\n}\n\n\nvoid\nchsrc_determine_chgtype (ChgType_t type)\n{\n  ProgStatus.chgtype =  chsrc_in_reset_mode() ? ChgType_Reset : type;\n}\n\n\n#define MSG_EN_PUBLIC_URL \"If the URL you specify is a public service, you are invited to contribute: chsrc issue\"\n#define MSG_CN_PUBLIC_URL \"若您指定的URL为公有服务，邀您参与贡献: chsrc issue\"\n\n#define MSG_EN_FULLY_AUTO \"Fully-Auto changed source. \"\n#define MSG_CN_FULLY_AUTO \"全自动换源完成\"\n\n#define MSG_EN_SEMI_AUTO  \"Semi-Auto changed source. \"\n#define MSG_CN_SEMI_AUTO  \"半自动换源完成\"\n\n#define MSG_EN_THANKS     \"Thanks to the mirror site: \"\n#define MSG_CN_THANKS     \"感谢镜像提供方: \"\n\n#define MSG_EN_BETTER     \"If you have a better source changing method , please help: chsrc issue\"\n#define MSG_CN_BETTER     \"若您有更好的换源方案，邀您帮助: chsrc issue\"\n\n#define MSG_EN_CONSTRAINT \"Implementation constraints require manual operation according to the above prompts. \"\n#define MSG_CN_CONSTRAINT \"因实现约束需按上述提示手工操作\"\n\n#define MSG_EN_STILL      \"Still need to operate manually according to the above prompts. \"\n#define MSG_CN_STILL      \"仍需按上述提示手工操作\"\n\n#define thank_mirror(msg) say(xy_2strcat(msg,purple(ENGLISH?source->mirror->abbr:source->mirror->name)))\n\n/**\n * @param source 可为NULL\n *\n * @dependency @gvar:ProgStatus.chgtype\n */\nvoid\nchsrc_conclude (Source_t *source)\n{\n  hr();\n\n  // fprintf (stderr, \"chsrc: now change type: %d\\n\", ProgStatus.chgtype);\n  if (chsrc_in_reset_mode())\n    {\n      // source_is_upstream (source)\n      char *msg = ENGLISH ? \"Has been reset to the upstream default source\" : \"已重置为上游默认源\";\n      chsrc_log (purple (msg));\n    }\n  else if (ChgType_Auto == ProgStatus.chgtype)\n    {\n      if (source)\n        {\n          if (source_is_userdefine (source))\n            {\n              char *msg = ENGLISH ? MSG_EN_FULLY_AUTO      MSG_EN_PUBLIC_URL \\\n                                  : MSG_CN_FULLY_AUTO \", \" MSG_CN_PUBLIC_URL;\n              chsrc_log (msg);\n            }\n          else\n            {\n              char *msg = ENGLISH ? MSG_EN_FULLY_AUTO      MSG_EN_THANKS \\\n                                  : MSG_CN_FULLY_AUTO \", \" MSG_CN_THANKS;\n              thank_mirror (msg);\n            }\n        }\n      else\n        {\n          char *msg = ENGLISH ? MSG_EN_FULLY_AUTO : MSG_CN_FULLY_AUTO;\n          chsrc_log (msg);\n        }\n    }\n  else if (ChgType_SemiAuto == ProgStatus.chgtype)\n    {\n      if (source)\n        {\n          if (source_is_userdefine (source))\n            {\n              char *msg = ENGLISH ? MSG_EN_SEMI_AUTO      MSG_EN_STILL      MSG_EN_PUBLIC_URL \\\n                                  : MSG_CN_SEMI_AUTO \", \" MSG_CN_STILL \"。\" MSG_CN_PUBLIC_URL;\n              chsrc_log (msg);\n            }\n          else\n            {\n              char *msg = ENGLISH ? MSG_EN_SEMI_AUTO      MSG_EN_STILL      MSG_EN_THANKS \\\n                                  : MSG_CN_SEMI_AUTO \", \" MSG_CN_STILL \"。\" MSG_CN_THANKS;\n              thank_mirror (msg);\n            }\n        }\n      else\n        {\n          char *msg = ENGLISH ? MSG_EN_SEMI_AUTO      MSG_EN_STILL \\\n                              : MSG_CN_SEMI_AUTO \", \" MSG_CN_STILL;\n          chsrc_log (msg);\n        }\n\n      char *msg = ENGLISH ? MSG_EN_BETTER : MSG_CN_BETTER;\n      chsrc_warn (msg);\n    }\n  else if (ChgType_Manual == ProgStatus.chgtype)\n    {\n      if (source)\n        {\n          if (source_is_userdefine (source))\n            {\n              char *msg = ENGLISH ? MSG_EN_CONSTRAINT      MSG_EN_PUBLIC_URL \\\n                                  : MSG_CN_CONSTRAINT \"; \" MSG_CN_PUBLIC_URL;\n              chsrc_log (msg);\n            }\n          else\n            {\n              char *msg = ENGLISH ? MSG_EN_CONSTRAINT      MSG_EN_THANKS \\\n                                  : MSG_CN_CONSTRAINT \", \" MSG_CN_THANKS;\n              thank_mirror (msg);\n            }\n        }\n      else\n        {\n          char *msg = ENGLISH ? MSG_EN_CONSTRAINT : MSG_CN_CONSTRAINT;\n          chsrc_log (msg);\n        }\n      char *msg = ENGLISH ? MSG_EN_BETTER : MSG_CN_BETTER;\n      chsrc_warn (msg);\n    }\n  else if (ChgType_Untested == ProgStatus.chgtype)\n    {\n      if (source)\n        {\n          if (source_is_userdefine (source))\n            {\n              char *msg = ENGLISH ? MSG_EN_PUBLIC_URL : MSG_CN_PUBLIC_URL;\n              chsrc_log (msg);\n            }\n          else\n            {\n              char *msg = ENGLISH ? MSG_EN_THANKS : MSG_CN_THANKS;\n              thank_mirror (msg);\n            }\n        }\n      else\n        {\n          char *msg = ENGLISH ? \"Auto changed source\" : \"自动换源完成\";\n          chsrc_log (msg);\n        }\n\n      char *msg = ENGLISH ? \"The method hasn't been tested or has any feedback, please report usage: chsrc issue\" : \"该换源步骤已实现但未经测试或存在任何反馈，请报告使用情况: chsrc issue\";\n      chsrc_warn (msg);\n    }\n  else\n    {\n      fprintf (stderr, \"chsrc: Wrong change type: %d\\n\", ProgStatus.chgtype);\n      xy_unreached();\n    }\n}\n\n\n/**\n * @brief 检测该 target 是否实现了用户所指定的 scope 能力\n *\n * @note 此函数目前只支持中文\n */\nvoid\nchsrc_check_scope_capability (Target_t *target)\n{\n  ScopeCapability_t cap = ScopeCap_Unknown;\n\n  char *msg1 = \"不支持\";\n  char *msg2 = \"换源，请使用 chsrc ls \";\n  char *msg3 = \" 查看支持的作用域以及默认作用域\";\n\n  char *aliases = target->aliases;\n  char *scope_name = NULL;\n\n  if (chsrc_in_project_scope_mode())\n    {\n      cap = target->scope_caps[ScopeCap_Slot_Project];\n\n      if (cap != ScopeCap_Able_And_Implemented)\n        {\n          scope_name = \"项目级\";\n          char* msg = xy_strcat (5, msg1, scope_name, msg2, aliases, msg3);\n          chsrc_error (msg);\n          exit (Exit_UserCause);\n        }\n    }\n  if (chsrc_in_user_scope_mode())\n    {\n      cap = target->scope_caps[ScopeCap_Slot_User];\n\n      if (cap != ScopeCap_Able_And_Implemented)\n        {\n          scope_name = \"用户级\";\n          char* msg = xy_strcat (5, msg1, scope_name, msg2, aliases, msg3);\n          chsrc_error (msg);\n          exit (Exit_UserCause);\n        }\n    }\n  if (chsrc_in_system_scope_mode())\n    {\n      cap = target->scope_caps[ScopeCap_Slot_System];\n\n      if (cap != ScopeCap_Able_And_Implemented)\n        {\n          scope_name = \"系统级\";\n          char* msg = xy_strcat (5, msg1, scope_name, msg2, aliases, msg3);\n          chsrc_error (msg);\n          exit (Exit_UserCause);\n        }\n    }\n}\n\n\n\nvoid\nchsrc_ensure_root ()\n{\n  char *euid = getenv (\"$EUID\");\n  if (NULL==euid)\n    {\n      char *buf = xy_run (\"id -u\", 0);\n      if (0!=atoi(buf)) goto not_root;\n      else return;\n    }\n  else\n    {\n      if (0!=atoi(euid)) goto not_root;\n      else return;\n    }\n\n  char *msg = NULL;\nnot_root:\n  msg = ENGLISH ? \"Use sudo before the command or switch to root to ensure the necessary permissions\"\n                         : \"请在命令前使用 sudo 或切换为root用户来保证必要的权限\";\n  chsrc_error (msg);\n  exit (Exit_UserCause);\n}\n\n\n#define RunOpt_Default                0x0000  // 默认若命令运行失败，直接退出\n#define RunOpt_Dont_Notify_On_Success 0x0010  // 运行成功不提示用户，只有运行失败时才提示用户\n#define RunOpt_No_Last_New_Line       0x0100  // 不输出最后的空行\n#define RunOpt_Dont_Abort_On_Failure  0x1000  // 命令运行失败也不退出\n\nstatic void\nchsrc_run (const char *cmd, int run_option)\n{\n  if (ProgStatus.chsrc_run_faas)\n    {\n      run_option |= RunOpt_Dont_Notify_On_Success|RunOpt_No_Last_New_Line;\n    }\n  else\n    {\n      if (ENGLISH)\n        xy_log_brkt (blue (App_Name), bdblue (\"RUN\"), blue (cmd));\n      else\n        xy_log_brkt (blue (App_Name), bdblue (\"运行\"), blue (cmd));\n    }\n\n  if (in_dry_run_mode())\n    {\n      return; // Dry Run 此时立即结束，并不真正执行\n    }\n\n  int status = system (cmd);\n  bool use_yellow_for_error = (run_option & RunOpt_Dont_Abort_On_Failure) != 0;\n\n  if (0==status)\n    {\n      if (! (RunOpt_Dont_Notify_On_Success & run_option))\n        {\n          log_cmd_result (true, status, use_yellow_for_error);\n        }\n    }\n  else\n    {\n      log_cmd_result (false, status, use_yellow_for_error);\n      if (! (run_option & RunOpt_Dont_Abort_On_Failure))\n        {\n          char *msg = ENGLISH ? \"Fatal error, forced end\" : \"关键错误，强制结束\";\n          chsrc_error (msg);\n          exit (Exit_ExternalError);\n        }\n    }\n\n  if (! (RunOpt_No_Last_New_Line & run_option))\n    {\n      br();\n    }\n}\n\n\nstatic void\nchsrc_run_as_a_service (const char *cmd)\n{\n  int run_option = RunOpt_Default;\n  ProgStatus.chsrc_run_faas = true;\n    run_option |= RunOpt_Dont_Notify_On_Success|RunOpt_No_Last_New_Line;\n    chsrc_run (cmd, run_option);\n  ProgStatus.chsrc_run_faas = false;\n}\n\n\n/**\n * @brief 以纯粹的方式直接运行命令，不做任何多余处理，\n *        命令执行前显示给用户，并保留所有输出给用户\n *\n * @return 返回命令的退出状态\n */\nint\nchsrc_run_directly (const char *cmd)\n{\n  if (ENGLISH)\n    xy_log_brkt (blue (App_Name), bdblue (\"RUN\"), blue (cmd));\n  else\n    xy_log_brkt (blue (App_Name), bdblue (\"运行\"), blue (cmd));\n\n  if (in_dry_run_mode())\n    {\n      return 0; // Dry Run 此时立即结束，并不真正执行\n    }\n  int status = system (cmd);\n  return status;\n}\n\n\n/**\n * @brief 在本目录创建一个临时文件\n *\n * @param[in]  filename    文件名，不包含后缀名\n * @param[in]  postfix     后缀名，需要自己加 '.'\n * @param[in]  loud        创建成功时是否提示用户\n * @param[out] tmpfilepath 生成的临时文件名，非 Windows 可以为 NULL\n *\n * @return 返回一个 FILE*，调用者需要关闭该文件\n */\nFILE *\nchsrc_make_tmpfile (char *filename, char *postfix, bool loud, char **tmpfilepath)\n{\n  char *tmpfile = NULL;\n  FILE *f = NULL;\n\n#ifdef XY_Build_On_Windows\n  /**\n   * Windows 上使用 GetTempPath 和 GetTempFileName 创建临时文件\n   * 这是 Windows API 推荐的标准方法\n   *\n   * 由于 GetTempFileName 不支持自定义后缀，我们需要：\n   * 1. 使用 GetTempFileName 生成唯一的临时文件名\n   * 2. 将其重命名为带有正确后缀的文件名（PowerShell 需要 .ps1 后缀）\n   */\n  char temp_path[MAX_PATH];\n  char temp_filename[MAX_PATH];\n\n  /* 获取系统临时目录 */\n  DWORD ret = GetTempPathA (MAX_PATH, temp_path);\n  if (ret == 0 || ret > MAX_PATH)\n    {\n      char *msg = CHINESE ? \"无法获取系统临时目录\" : \"Unable to get system temp directory\";\n      chsrc_error2 (msg);\n      exit (Exit_ExternalError);\n    }\n\n  /* 生成唯一的临时文件名 (会自动创建文件) */\n  ret = GetTempFileNameA (temp_path, \"chsrc_\", 0, temp_filename);\n  if (ret == 0)\n    {\n      char *msg = CHINESE ? \"无法生成临时文件名\" : \"Unable to generate temporary filename\";\n      chsrc_error2 (msg);\n      exit (Exit_ExternalError);\n    }\n\n  tmpfile = xy_strcat (4, temp_filename, \"_\", filename, postfix);\n\n  /* 删除 GetTempFileName 自动创建的文件 */\n  DeleteFileA (temp_filename);\n\n  /* 创建带有正确后缀的文件 */\n  f = fopen (tmpfile, \"w+\");\n\n  if (!f)\n    {\n      char *msg = CHINESE ? \"无法创建临时文件: \" : \"Unable to create temporary file: \";\n            msg = xy_2strcat (msg, tmpfile);\n      chsrc_error2 (msg);\n      exit (Exit_ExternalError);\n    }\n#else\n  /**\n   * 非 Windows 平台使用 mkstemps() 创建临时文件\n   * 这是 POSIX 标准方法，可以指定后缀名\n   */\n  tmpfile = xy_strcat (5, \"/tmp/\", \"chsrc_tmp_\", filename, \"_XXXXXX\", postfix);\n  size_t postfix_len = strlen (postfix);\n\n  /* mkstemps() 会原子性地创建文件并返回文件描述符 */\n  int fd = mkstemps (tmpfile, postfix_len);\n\n  if (fd == -1)\n    {\n      char *msg = CHINESE ? \"无法创建临时文件: \" : \"Unable to create temporary file: \";\n            msg = xy_2strcat (msg, tmpfile);\n      chsrc_error2 (msg);\n      exit (Exit_ExternalError);\n    }\n\n  f = fdopen (fd, \"w+\");\n\n  if (!f)\n    {\n      close (fd);  /* 关闭文件描述符以避免泄漏 */\n      char *msg = CHINESE ? \"无法打开临时文件: \" : \"Unable to open temporary file: \";\n            msg = xy_2strcat (msg, tmpfile);\n      chsrc_error2 (msg);\n      exit (Exit_ExternalError);\n    }\n#endif\n\n  if (loud)\n    {\n      char *msg = CHINESE ? \"已创建临时文件: \" : \"Temporary file created: \";\n            msg = xy_2strcat (msg, tmpfile);\n      chsrc_succ2 (msg);\n    }\n\n  /**\n   * 允许生成文件后不了解其文件名，调用者只了解 FILE*\n   * 这样的话，其实是无法删除该文件的，但是生成在 /tmp 目录下我们恰好可以不用清理\n   * 但是在 Windows 上，就没有办法了，所以我们禁止在 Windows 上不指定返回出的临时文件名\n   */\n  if (xy.on_windows && !tmpfilepath)\n    {\n      chsrc_error2 (\"在 Windows 上，创建临时文件时必须指定返回的临时文件名\");\n      xy_unreached();\n    }\n\n  if (tmpfilepath)\n    {\n      *tmpfilepath = xy_normalize_path (xy_strdup (tmpfile));\n    }\n\n  return f;\n}\n\n\n/**\n * 以 bash file.bash 的形式运行脚本内容\n */\nvoid\nchsrc_run_as_bash_file (const char *script_content)\n{\n  char *tmpfile = NULL;\n  FILE *f = chsrc_make_tmpfile (\"bash_script\", \".bash\", false, &tmpfile);\n  fwrite (script_content, strlen (script_content), 1, f);\n  fclose (f);\n  // chmod (tmpfile, 0700);\n  char *msg = CHINESE ? \"即将执行 Bash 脚本内容:\" : \"The Bash script content will be executed:\";\n  chsrc_note2 (msg);\n  println (faint(script_content));\n  char *cmd = xy_2strcat (\"bash \", tmpfile);\n  chsrc_run (cmd, RunOpt_Dont_Abort_On_Failure);\n  remove (tmpfile);\n  free (tmpfile);  /* 释放 tmpfile 路径内存 */\n}\n\n\n/**\n * 以 sh file.sh 的形式运行脚本内容\n */\nvoid\nchsrc_run_as_sh_file (const char *script_content)\n{\n  char *tmpfile = NULL;\n  FILE *f = chsrc_make_tmpfile (\"sh_script\", \".sh\", false, &tmpfile);\n  fwrite (script_content, strlen (script_content), 1, f);\n  fclose (f);\n  // chmod (tmpfile, 0700);\n  char *msg = CHINESE ? \"即将执行 sh 脚本内容:\" : \"The sh script content will be executed:\";\n  chsrc_note2 (msg);\n  println (faint(script_content));\n  char *cmd = xy_2strcat (\"sh \", tmpfile);\n  chsrc_run (cmd, RunOpt_Dont_Abort_On_Failure);\n  remove (tmpfile);\n  free (tmpfile);\n}\n\n\n/**\n * 以 pwsh file.ps1 的形式运行脚本内容\n */\nvoid\nchsrc_run_as_pwsh_file (const char *script_content)\n{\n  char *tmpfile = NULL;\n  FILE *f = chsrc_make_tmpfile (\"pwsh_script\", \".ps1\", false, &tmpfile);\n  fwrite (script_content, strlen (script_content), 1, f);\n  fclose (f);\n  char *msg = CHINESE ? \"即将执行 PowerShell (v7以上) 脚本内容:\" : \"The PowerShell script content will be executed:\";\n  chsrc_note2 (msg);\n  println (faint(script_content));\n  char *cmd = xy_2strcat (\"pwsh \", tmpfile);\n  chsrc_run (cmd, RunOpt_Dont_Abort_On_Failure);\n  remove (tmpfile);\n  free (tmpfile);\n}\n\n\n/**\n * 以 powershell file.ps1 的形式运行脚本内容\n */\nvoid\nchsrc_run_as_powershellv5_file (const char *script_content)\n{\n  char *tmpfile = NULL;\n  FILE *f = chsrc_make_tmpfile (\"psv5_script\", \".ps1\", false, &tmpfile);\n  fwrite (script_content, strlen (script_content), 1, f);\n  fclose (f);\n  char *msg = CHINESE ? \"即将执行 PowerShell v5 脚本内容:\" : \"The PowerShell v5 script content will be executed:\";\n  chsrc_note2 (msg);\n  println (faint(script_content));\n  // -ExecutionPolicy Bypass\n  char *cmd = xy_2strcat (\"powershell -File \", tmpfile);\n  chsrc_run (cmd, RunOpt_Dont_Abort_On_Failure);\n  remove (tmpfile);\n  free (tmpfile);\n}\n\n\n/**\n * 使用 pwsh 或 旧的 powershell (v5) 运行脚本内容，优先使用 pwsh\n */\nvoid\nchsrc_run_as_powershell_file (const char *script_content)\n{\n  // if (chsrc_check_program_quietly_when_exist (\"pwsh\"))\n  if (chsrc_check_program_quietly (\"pwsh\"))\n    {\n      chsrc_run_as_pwsh_file (script_content);\n    }\n  else\n    {\n      chsrc_alert2 (CHINESE ? \"未检测到 PowerShell 7 及以上版本，默认使用 PowerShell v5\"\n                            : \"PowerShell 7 or above not detected, switch to PowerShell v5\");\n      chsrc_run_as_powershellv5_file (script_content);\n    }\n}\n\n\n/**\n * @param cmdline 需要自己负责转义\n *\n * @danger 需要经过 Bash 的转义，很容易出错，不要用这个函数\n */\nXY_Deprecate_This(\"Don't use this function\")\nvoid\nchsrc_run_in_inline_bash_shell (const char *cmdline)\n{\n  char *cmd = xy_strcat (3, \"bash -c '\", cmdline, \"'\");\n  chsrc_run (cmd, RunOpt_Dont_Abort_On_Failure);\n}\n\n\n/**\n * @param cmdline 需要自己负责转义\n *\n * @danger 需要经过 PowerShell 的转义，很容易出错，不要用这个函数\n */\nXY_Deprecate_This(\"Don't use this function\")\nvoid\nchsrc_run_in_inline_pwsh_shell (const char *cmdline)\n{\n  char *cmd = xy_strcat (3, \"pwsh -Command '\", cmdline, \"'\");\n  chsrc_run (cmd, RunOpt_Dont_Abort_On_Failure);\n}\n\n\nstatic void\nchsrc_view_env (const char *var1, ...)\n{\n  char *cmd = NULL;\n  const char *var = var1;\n\n  va_list vars;\n  va_start (vars, var1);\n\n  bool first = true;\n  while (var)\n    {\n      if (xy.on_windows)\n        {\n          if (first)\n            {\n              cmd = xy_strcat (3, \"set \", var, \" \");\n              first = false;\n            }\n          else\n            {\n              cmd = xy_strcat (4, cmd, \"& set \", var, \" \");\n            }\n        }\n      else\n       {\n          if (first)\n            {\n              cmd = xy_strcat (5, \"echo \", var, \"=$\", var, \" \");\n              first = false;\n            }\n          else\n            {\n              cmd = xy_strcat (6, cmd, \"; echo \", var, \"=$\", var, \" \");\n            }\n        }\n      var = va_arg (vars, const char *);\n    }\n\n  va_end (vars);\n\n  if (var1)\n    {\n      /**\n       * 不用 chsrc_run()，因为在Windows上，set在遇到环境变量未定义时会返回非0，导致 chsrc_run() 报告运行失败\n       * 这个错误过于醒目。我们应该像在 sh 一样，默默地没有输出即可，而不是报错\n       */\n      // chsrc_run (cmd, RunOpt_Dont_Notify_On_Success|RunOpt_No_Last_New_Line|RunOpt_Dont_Abort_On_Failure);\n      int status = system (cmd);\n      if (status!=0) { xy_noop(); }\n    }\n  else\n    {\n      /* 必须给一个参数 */\n      xy_unreached();\n    }\n}\n\n\nstatic void\nchsrc_view_file (const char *path)\n{\n  char *cmd = NULL;\n  path = xy_normalize_path (path);\n  if (xy.on_windows)\n    {\n      cmd = xy_2strcat (\"type \", path);\n    }\n  else\n    {\n      cmd = xy_2strcat (\"cat \", path);\n    }\n\n  chsrc_run_as_a_service (cmd);\n}\n\nstatic void\nchsrc_ensure_dir (const char *dir)\n{\n  dir = xy_normalize_path (dir);\n\n  if (xy_dir_exist (dir))\n    {\n      return;\n    }\n\n  // 不存在就生成\n  char *mkdir_cmd = NULL;\n  if (xy.on_windows)\n    {\n      mkdir_cmd = \"md \";  // 已存在时返回 errorlevel = 1\n    }\n  else\n    {\n      mkdir_cmd = \"mkdir -p \";\n    }\n  char *cmd = xy_2strcat (mkdir_cmd, dir);\n  cmd = xy_quiet_cmd (cmd);\n\n  chsrc_run_as_a_service (cmd);\n\n  char *msg = ENGLISH ? \"Directory doesn't exist, created automatically \" : \"目录不存在，已自动创建 \";\n  chsrc_alert2 (xy_2strcat (msg, dir));\n}\n\n\nstatic void\nchsrc_append_to_file (const char *str, const char *filename)\n{\n  if (in_dry_run_mode())\n    {\n      goto log_anyway;\n    }\n\n  char *file = xy_normalize_path (filename);\n  char *dir = xy_parent_dir (file);\n  chsrc_ensure_dir (dir);\n\n  FILE *f = fopen (file, \"a\");\n  if (NULL==f)\n    {\n      char *msg = ENGLISH ? xy_2strcat (\"Unable to open file to write: \", file)\n                          : xy_2strcat (\"无法打开文件以写入: \", file);\n      chsrc_error2 (msg);\n      exit (Exit_UserCause);\n    }\n\n  size_t len = strlen (str);\n\n  size_t ret = fwrite (str, len, 1, f);\n  if (ret != 1)\n    {\n      char *msg = ENGLISH ? xy_2strcat (\"Write failed to \", file)\n                          : xy_2strcat (\"写入文件失败: \", file);\n      chsrc_error2 (msg);\n      exit (Exit_UserCause);\n    }\n\n  fclose (f);\n\nlog_anyway:\n  /* 输出recipe指定的文件名 */\n  chsrc_log_write (filename, false);\n\n  /*\n  char *cmd = NULL;\n  if (xy.on_windows)\n    {\n      cmd = xy_strcat (4, \"echo \", str, \" >> \", file);\n    }\n  else\n    {\n      cmd = xy_strcat (4, \"echo '\", str, \"' >> \", file);\n    }\n  chsrc_run_a_service (cmd);\n  */\n}\n\n/**\n * @note 本函数不会在 `str` 末尾添加换行符，所以你可能需要在 `str` 中手动添加\n */\nstatic void\nchsrc_prepend_to_file (const char *str, const char *filename)\n{\n  if (in_dry_run_mode())\n    {\n      goto log_anyway;\n    }\n\n  char *file = xy_normalize_path (filename);\n\n  char *file_content = xy_file_read (file);\n  char *content = xy_2strcat (str, file_content);\n\n  FILE *f = fopen (file, \"w\");\n\n  if (f)\n    {\n      fwrite (content, 1, strlen (content), f);\n      fclose (f);\n    }\n  else\n    {\n      chsrc_error2 (\"文件打开失败\");\n      exit (Exit_UserCause);\n    }\n\nlog_anyway:\n  /* 输出recipe指定的文件名 */\n  chsrc_log_write (filename, false);\n}\n\nstatic void\nchsrc_overwrite_file (const char *str, const char *filename)\n{\n  if (in_dry_run_mode())\n    {\n      goto log_anyway;\n    }\n\n  char *file = xy_normalize_path (filename);\n  char *dir = xy_parent_dir (file);\n  chsrc_ensure_dir (dir);\n\n  FILE *f = fopen (file, \"w\");\n  if (NULL==f)\n    {\n      char *msg = ENGLISH ? xy_2strcat (\"Unable to open file to overwrite: \", file)\n                          : xy_2strcat (\"无法打开文件以覆盖: \", file);\n      chsrc_error2 (msg);\n      exit (Exit_UserCause);\n    }\n\n  size_t len = strlen (str);\n  size_t ret = fwrite (str, len, 1, f);\n  if (ret != 1)\n    {\n      fclose (f);\n      char *msg = ENGLISH ? xy_2strcat (\"Write failed to \", file)\n                          : xy_2strcat (\"写入文件失败: \", file);\n      chsrc_error2 (msg);\n      exit (Exit_UserCause);\n    }\n\n  fclose (f);\n\nlog_anyway:\n  /* 输出recipe指定的文件名 */\n  chsrc_log_write (filename, true);\n}\n\nstatic void\nchsrc_backup (const char *path)\n{\n  if (in_dry_run_mode())\n    {\n      goto log_anyway;\n    }\n\n  char *cmd = NULL;\n  bool exist = xy_file_exist (path);\n\n  if (!exist)\n    {\n      char *msg = ENGLISH ? \"File doesn't exist, skip backup: \" : \"文件不存在,跳过备份: \";\n      chsrc_alert2 (xy_2strcat (msg, path));\n      return;\n    }\n\n  if (xy.on_bsd || xy.on_macos)\n    {\n      /* BSD 和 macOS 的 cp 不支持 --backup 选项 */\n      cmd = xy_strcat (5, \"cp -f \", path, \" \", path, \".bak\");\n    }\n  else if (xy.on_windows)\n    {\n      /**\n       * @note /Y 表示覆盖\n       * @note 默认情况下会输出一个 \"已复制  1个文件\"\n       */\n      cmd = xy_strcat (5, \"copy /Y \", path, \" \", path, \".bak 1>nul\");\n    }\n  else\n    {\n      /**\n       * @see https://github.com/RubyMetric/chsrc/issues/152#issuecomment-2542673273\n       *\n       * busybox cp 会在 stderr 输出 unrecognized option: version\n       * stderr 导入到 stdout，以便我们 xy_run() 可以接受到输出\n       *\n       */\n      char *ver = xy_run (\"cp --version 2>&1\", 1);\n      /* cp (GNU coreutils) 9.4 */\n      if (strstr (ver, \"GNU coreutils\"))\n        {\n          cmd = xy_strcat (5, \"cp \", path, \" \", path, \".bak --backup='t'\");\n        }\n      else\n        {\n          /* 非 GNU 的 cp 可能不支持 --backup ，如 busybox cp */\n          cmd = xy_strcat (5, \"cp -f \", path, \" \", path, \".bak\");\n        }\n    }\n\n  chsrc_run_as_a_service (cmd);\n\nlog_anyway:\n  chsrc_log_backup (path);\n}\n\n\n/**\n * 检查过程中全程保持安静\n */\nstatic char *\nchsrc_get_cpuarch ()\n{\n  char *ret;\n  char *msg;\n\n#if XY_Build_On_Windows\n  SYSTEM_INFO info;\n  GetSystemInfo (&info);\n  WORD num = info.wProcessorArchitecture;\n  switch (num)\n    {\n      case PROCESSOR_ARCHITECTURE_AMD64:\n        ret = \"x86_64\"; break;\n      case PROCESSOR_ARCHITECTURE_ARM:\n        ret = \"arm\";    break;\n      case PROCESSOR_ARCHITECTURE_INTEL:\n        ret = \"x86\";    break;\n      case PROCESSOR_ARCHITECTURE_IA64:\n        ret = \"IA-64\";  break;\n      case PROCESSOR_ARCHITECTURE_UNKNOWN:\n      default:\n        msg = ENGLISH ? \"Unable to detect CPU type\" : \"无法检测到CPU类型\";\n        chsrc_error (msg);\n        exit (Exit_UserCause);\n    }\n  return ret;\n#else\n\n  bool exist;\n\n  exist = chsrc_check_program_quietly (\"arch\");\n  if (exist)\n    {\n      ret = xy_run (\"arch\", 0);\n      return ret;\n    }\n\n  exist = chsrc_check_program_quietly (\"uname\");\n  if (exist)\n    {\n      ret = xy_run (\"uname -m\", 0);\n      return ret;\n    }\n  else\n    {\n      msg = ENGLISH ? \"Unable to detect CPU type\" : \"无法检测到CPU类型\";\n      chsrc_error (msg);\n      exit (Exit_UserCause);\n    }\n#endif\n}\n\n\nstatic int\nchsrc_get_cpucore ()\n{\n  int cores = 2;\n\n#if XY_Build_On_Windows\n  SYSTEM_INFO info;\n  GetSystemInfo (&info);\n  DWORD num = info.dwNumberOfProcessors;\n  cores = (int)num;\n#else\n  long num = sysconf(_SC_NPROCESSORS_ONLN);\n  cores = (int)num;\n#endif\n\n  return cores;\n}\n"
  },
  {
    "path": "src/framework/helper.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Name     : helper.c\n * File Authors  : 曾奥然 <ccmywish@qq.com>\n * Contributors  : Nul None <nul@none.org>\n * Created On    : <2025-07-14>\n * Last Modified : <2025-10-28>\n *\n * For chefs (recipe makers) and sometimes framewoker\n * to do some work not releated to OS operations\n * ------------------------------------------------------------*/\n\nbool\nhp_is_url (const char *str)\n{\n  return (xy_str_start_with (str, \"http://\") || xy_str_start_with (str, \"https://\"));\n}\n\n/**\n * @return 一律返回新字符串\n */\nchar *\nhp_remove_trailing_slash (char *str)\n{\n  char *newstr = xy_strdup (str);\n  size_t len = strlen (newstr);\n  if (len > 0 && newstr[len - 1] == '/')\n    newstr[len - 1] = '\\0';\n  return newstr;\n}\n\n/**\n * @return 一律返回新字符串\n */\nchar *\nhp_ensure_trailing_slash (char *str)\n{\n  size_t len = strlen (str);\n  if (len == 0 || str[len - 1] == '/')\n    return xy_strdup (str);\n\n  return xy_2strcat (str, \"/\");\n}\n"
  },
  {
    "path": "src/framework/mirror.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Name     : mirror.c\n * File Authors  : @ccmywish\n *               | @G_I_Y\n * Contributors  : @livelycode36\n *               | @jialinlvcn\n *               | @Mikachu2333\n *               | @BingChunMoLi\n *               |\n * Created On    : <2023-08-29>\n * Last Modified : <2025-10-07>\n *\n * 通用镜像站\n * ------------------------------------------------------------*/\n\n#define Big_File_ubuntu     \"/18.04/ubuntu-18.04.6-desktop-amd64.iso\"       // 2.3 GB\n#define Big_File_ctan       \"/systems/texlive/Images/texlive.iso\"           // 4.8 GB\n#define Big_File_archlinux  \"/iso/latest/archlinux-x86_64.iso\"              // 800 MB\n#define Big_File_deepin     \"/20.9/deepin-desktop-community-20.9-amd64.iso\" // 4 GB\n\n/**\n * 教育网镜像\n *\n * @sync https://github.com/RubyMetric/chsrc/wiki\n *\n * 排序部分参考 https://github.com/mirrorz-org/oh-my-mirrorz\n */\nMirrorSite_t MirrorZ =\n{\n  IS_GeneralMirrorSite,\n  \"mirrorz\", \"MirrorZ\",  \"校园网联合镜像站(MirrorZ)\", \"https://mirrors.cernet.edu.cn/\",\n  {NotSkip,  NA, NA, \"https://mirrors.cernet.edu.cn/ubuntu/dists/noble/Contents-amd64.gz\", ROUGH}\n},\n\nTuna =\n{\n  IS_GeneralMirrorSite,\n  \"tuna\", \"TUNA\", \"清华大学开源软件镜像站\", \"https://mirrors.tuna.tsinghua.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.tuna.tsinghua.edu.cn/speedtest/1000mb.bin\", ROUGH}\n},\n\n/**\n * @note 2025-03-17 SJTUG 共设两台服务器。思源服务器同步新镜像，致远服务器兼容原 SJTU 镜像站。\n * @note 有些target（例如flathub）思源站的兼容性不好，可以考虑将两个服务器分开测试\n */\n\nSjtug_Zhiyuan =\n{\n  IS_GeneralMirrorSite,\n  \"sjtu-zy\", \"SJTUG-zhiyuan\", \"上海交通大学致远镜像站\", \"https://mirrors.sjtug.sjtu.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.sjtug.sjtu.edu.cn/ctan\" Big_File_ctan, ROUGH}\n},\n\nSjtug_Siyuan =\n{\n  IS_GeneralMirrorSite,\n  \"sjtu-sy\", \"SJTUG-siyuan\", \"上海交通大学思源镜像站\", \"https://mirror.sjtu.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirror.sjtu.edu.cn/ctan\" Big_File_ctan, ROUGH}\n},\n\nBfsu =\n{\n  IS_GeneralMirrorSite,\n  \"bfsu\", \"BFSU\", \"北京外国语大学开源软件镜像站\", \"https://mirrors.bfsu.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.bfsu.edu.cn/speedtest/1000mb.bin\", ROUGH}\n},\n\nUstc =\n{\n  IS_GeneralMirrorSite,\n  \"ustc\", \"USTC\", \"中国科学技术大学开源软件镜像\", \"https://mirrors.ustc.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.ustc.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nZju =\n{\n  IS_GeneralMirrorSite,\n  \"zju\", \"ZJU\", \"浙江大学开源软件镜像站\", \"https://mirrors.zju.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.zju.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nJlu =\n{\n  IS_GeneralMirrorSite,\n  \"jlu\", \"JLU\", \"吉林大学开源镜像站\", \"https://mirrors.jlu.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.jlu.edu.cn/_static/speedtest.bin\", ROUGH}\n},\n\nLzuoss =\n{\n  IS_GeneralMirrorSite,\n  \"lzu\", \"LZUOSS\", \"兰州大学开源社区镜像站\", \"https://mirror.lzu.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirror.lzu.edu.cn/CTAN\" Big_File_ctan, ROUGH}\n},\n\nPku =\n{\n  IS_GeneralMirrorSite,\n  \"pku\", \"PKU\", \"北京大学开源镜像站\", \"https://mirrors.pku.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.pku.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nBjtu =\n{\n  IS_GeneralMirrorSite,\n  \"bjtu\", \"BJTU\", \"北京交通大学自由与开源软件镜像站\", \"https://mirror.bjtu.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirror.bjtu.edu.cn/archlinux\" Big_File_archlinux, ROUGH}\n},\n\nSustech =\n{\n  IS_GeneralMirrorSite,\n  \"sustech\", \"SUSTech\", \"南方科技大学开源软件镜像站\", \"https://mirrors.sustech.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.sustech.edu.cn/site/speedtest/1000mb.bin\", ROUGH}\n},\n\nNju =\n{\n  IS_GeneralMirrorSite,\n  \"nju\", \"NJU\", \"南京大学开源镜像站\", \"https://mirrors.nju.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.nju.edu.cn/archlinux\" Big_File_archlinux, ROUGH}\n},\n\nXjtu =\n{\n  IS_GeneralMirrorSite,\n  \"xjtu\", \"XJTU\", \"西安交通大学软件镜像站\", \"https://mirrors.xjtu.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.xjtu.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nHust =\n{\n  IS_GeneralMirrorSite,\n  \"hust\", \"HUST\", \"华中科技大学开源镜像站\", \"https://mirrors.hust.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.hust.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nIscas =\n{\n  IS_GeneralMirrorSite,\n  \"iscas\", \"ISCAS\", \"中科院软件所智能软件研究中心开源镜像站\", \"https://mirror.iscas.ac.cn/\",\n  {NotSkip, NA, NA, \"https://mirror.iscas.ac.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nHit =\n{\n  IS_GeneralMirrorSite,\n  \"hit\", \"HIT\", \"哈尔滨工业大学开源软件镜像站\", \"https://mirrors.hit.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.hit.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nScau =\n{\n  IS_GeneralMirrorSite,\n  \"scau\", \"SCAU\", \"华南农业大学开源软件镜像站\", \"https://mirrors.scau.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.scau.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nNJTech =\n{\n  IS_GeneralMirrorSite,\n  \"njtech\", \"NJTech\", \"南京工业大学开源软件镜像站\", \"https://mirrors.njtech.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.njtech.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nNyist =\n{\n  IS_GeneralMirrorSite,\n  \"nyist\", \"NYIST\", \"南阳理工学院开源软件镜像站\", \"https://mirror.nyist.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirror.nyist.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nSdu =\n{\n  IS_GeneralMirrorSite,\n  \"sdu\", \"SDU\", \"山东大学镜像站\", \"https://mirrors.sdu.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.sdu.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nQlu =\n{\n  IS_GeneralMirrorSite,\n  \"qlu\", \"QLU\", \"齐鲁工业大学开源镜像站\", \"https://mirrors.qlu.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.qlu.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nCqupt =\n{\n  IS_GeneralMirrorSite,\n  \"cqupt\", \"CQUPT\", \"重庆邮电大学开源镜像站\", \"https://mirrors.cqupt.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.cqupt.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\n/**\n * @note 2023-09-05 封杀策略过严，谨慎使用\n */\nCqu =\n{\n  IS_GeneralMirrorSite,\n  \"cqu\", \"CQU\", \"重庆大学开源软件镜像站\", \"https://mirrors.cqu.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.cqu.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nNeosoft =\n{\n  IS_GeneralMirrorSite,\n  \"neosoft\", \"Neosoft\", \"大连东软信息学院开源镜像站\", \"https://mirrors.neusoft.edu.cn/\",\n  {NotSkip, NA, NA, \"https://mirrors.neusoft.edu.cn/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n};\n\n\n\n/**\n * 商业公司提供的源\n */\nMirrorSite_t Ali =\n{\n  IS_GeneralMirrorSite,\n  \"ali\", \"Ali OPSX Public\", \"阿里巴巴开源镜像站(公网)\", \"https://developer.aliyun.com/mirror/\",\n  {NotSkip, NA, NA, \"https://mirrors.aliyun.com/ubuntu/ls-lR.gz\", ROUGH} // 31MB左右\n},\n/*\n// https://mirrors.cloud.aliyuncs.com/\nAli_ECS_VPC =\n{\n  IS_GeneralMirrorSite,\n  \"ali-ECS-VPC\", \"Ali OPSX ECS VPC\", \"阿里巴巴开源镜像站(ECS VPC网络)\", \"https://developer.aliyun.com/mirror/\",\n  {NotSkip, NA, NA, \"https://mirrors.cloud.aliyuncs.com/deepin-cd\" Big_File_deepin, ROUGH}\n},\n\n// https://mirrors.aliyuncs.com/\nAli_ECS_classic =\n{\n  IS_GeneralMirrorSite,\n  \"ali-ECS\", \"Ali OPSX ECS\", \"阿里巴巴开源镜像站(ECS 经典网络)\", \"https://developer.aliyun.com/mirror/\",\n  {NotSkip, NA, NA, \"https://mirrors.aliyuncs.com/deepin-cd\" Big_File_deepin, ROUGH}\n},\n*/\n\nTencent =\n{\n  IS_GeneralMirrorSite,\n  \"tencent\", \"Tencent Public\", \"腾讯软件源(公网)\", \"https://mirrors.tencent.com/\",\n  {NotSkip, NA, NA, \"https://mirrors.cloud.tencent.com/mariadb/mariadb-12.1.0/winx64-packages/mariadb-12.1.0-winx64-debugsymbols.zip\", ROUGH} // 110MB左右\n},\n/*\nTencent_Intra =\n{\n  IS_GeneralMirrorSite,\n  \"tencent-intra\", \"Tencent Intranet\",  \"腾讯软件源(内网)\", \"https://mirrors.tencent.com/\",\n  {NotSkip, NA, NA, \"https://mirrors.cloud.tencentyun.com/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n*/\n\nHuawei =\n{\n  IS_GeneralMirrorSite,\n  \"huawei\",  \"Huawei Cloud\", \"华为开源镜像站\",  \"https://mirrors.huaweicloud.com/\",\n  {NotSkip, NA, NA, \"https://mirrors.huaweicloud.com/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nHuaweiCDN =\n{\n  IS_GeneralMirrorSite,\n  \"huawei-cdn\",  \"Huawei Cloud CDN\", \"华为开源镜像站(CDN)\",  \"https://repo.huaweicloud.com/\",\n  {NotSkip, NA, NA, \"https://repo.huaweicloud.com/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n\nVolcengine =\n{\n  IS_GeneralMirrorSite,\n  \"volc\", \"Volcengine\", \"火山引擎开源软件镜像站(公网)\", \"https://developer.volcengine.com/mirror/\",\n  {NotSkip, NA, NA, \"https://mirrors.volces.com/ubuntu-releases\" Big_File_ubuntu, ROUGH}\n},\n/*\nVolceengine_Intra =\n{\n  IS_GeneralMirrorSite,\n  \"volc-intra\",  \"Volcengine Intranet\", \"火山引擎开源软件镜像站(内网)\",\n  \"https://developer.volcengine.com/mirror/\",\n  \"https://mirrors.ivolces.com/ubuntu-releases\" Big_File_ubuntu, ROUGH},\n*/\n\n\n/**\n * @note 2025-06-20 网易开源镜像站的速度始终过低，不建议再使用\n */\nNetease =\n{\n  IS_GeneralMirrorSite,\n  \"netease\", \"Netease\", \"网易开源镜像站\", \"https://mirrors.163.com/\",\n  {NotSkip, NA, NA, \"https://mirrors.163.com/deepin-cd\" Big_File_deepin, ROUGH}\n},\n\n/**\n * @note 2025-06-20 搜狐开源镜像站的速度始终过低，不建议再使用\n */\nSohu =\n{\n  IS_GeneralMirrorSite,\n  \"sohu\", \"SOHU\", \"搜狐开源镜像站\", \"https://mirrors.sohu.com/\",\n  {NotSkip, NA, NA, \"https://mirrors.sohu.com/deepin-cd\" Big_File_deepin, ROUGH}\n};\n"
  },
  {
    "path": "src/framework/struct.h",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Name     : struct.h\n * File Authors  : @ccmywish\n *               | @G_I_Y\n * Contributors  : @livelycode36\n *               |\n * Created On    : <2023-08-29>\n * Last Modified : <2026-02-24>\n *\n * chsrc struct\n * ------------------------------------------------------------*/\n\ntypedef struct ProviderSpeedMeasureInfo_t\n{\n  bool  skip;           /* 是否默认跳过 */\n  char *skip_reason_CN; /* 跳过的原因（中文）*/\n  char *skip_reason_EN; /* 跳过的原因（英文）*/\n  char *url;            /* 测速链接 */\n  bool  accurate;       /* 是否为精准测速，上游源和专用镜像站为 ACCURATE，通用镜像站为 ROUGH */\n}\nProviderSpeedMeasureInfo_t;\n\n#define SKIP    true\n#define NotSkip false\n#define ToFill  NULL\n#define NA\t\t  NULL\n\n#define ACCURATE true\n#define ROUGH    false\n\ntypedef enum ProviderType_t\n{\n  IS_GeneralMirrorSite,   /* 通用镜像站 */\n  IS_DedicatedMirrorSite, /* 专用镜像站 */\n  IS_UpstreamProvider,    /* 上游默认源 */\n  IS_UserDefinedProvider, /* 用户提供   */\n}\nProviderType_t;\n\ntypedef struct SourceProvider_t\n{\n  const ProviderType_t type; /* 类型 */\n  const char *code; /* 用于用户指定某一 Provider */\n  const char *abbr; /* 需要使用 Provider 的英文名时，用这个代替，因为大部分 Provider 没有提供正式的英文名 */\n  const char *name; /* Provider 中文名 */\n  const char *site; /* Provider 首页   */\n  ProviderSpeedMeasureInfo_t psmi;\n}\nSourceProvider_t;\n\ntypedef SourceProvider_t MirrorSite_t;\n\nSourceProvider_t UpstreamProvider =\n{\n  IS_UpstreamProvider,\n  /* 引入新的上游默认源时，请使下面第一行的前三个字段保持不变，只添加第四个字段 */\n  \"upstream\", \"Upstream\", \"上游默认源\", NULL,\n  /* 引入新的上游默认源时，请完全修改下面这个结构体，可使用 def_need_measure_info 宏 */\n  {SKIP, \"URL未知，邀您参与贡献!\", \"URL unknown, welcome to contribute!\", NULL, ACCURATE}\n};\n\n#define def_need_measure_info   {SKIP, \"缺乏较大的测速对象，邀您参与贡献!\", \"Lack of large object URL, welcome to contribute!\", NULL, ACCURATE}\n\nSourceProvider_t UserDefinedProvider =\n{\n  IS_UserDefinedProvider,\n  \"user\", \"用户自定义\", \"用户自定义\", NULL,\n  {SKIP, \"用户自定义源不测速\", \"SKIP for user-defined source\", NULL, ACCURATE}\n};\n\n\ntypedef struct Source_t\n{\n  union {\n    SourceProvider_t *provider;\n    MirrorSite_t     *mirror;\n  };\n  /* 用于换源的 URL，也称 repoURL */\n  char *url;\n\n  /* 对该 source 的专用测速链接，这就是精准测速，也称 smURL */\n  char *speed_measure_url;\n}\nSource_t;\n\n/* 不用给专用测速链接，因为 Upstream 的整体测速链接已是精准测速 */\n#define DelegateToUpstream  NULL\n/* 不用给专用测速链接，因为该镜像站是专用镜像站，其整体测速链接已是精准测速 */\n#define DelegateToMirror    NULL\n/* 看到该注释的贡献者，你可以帮忙寻找专用测速链接 */\n#define NeedContribute      NULL\n/* 由 prelude() 填充 */\n#define FeedByPrelude NULL\n\n\n/**\n * 换源的作用域\n *\n * 在 chsrc v0.2.4.2 以前，我们一直使用的是 `-local` 这个选项，其含义是启用 *项目级* 换源\n *\n * 1. 默认不使用该选项时，含义是 *全局* 换源，\n *\n *    全局分为 (1)系统级 (2)用户级\n *\n *    大多数第三方配置软件往往默认进行的是 *用户级* 的配置。所以 chsrc 首先将尝试使用 *用户级* 配置\n *\n * 2. 若不存在 *用户级* 的配置，chsrc 将采用 *系统级* 的配置\n *\n * 3. 最终效果本质由第三方软件决定，如 poetry 默认实现的就是项目级的换源\n *\n * 但是后来，我们认为非 -local 时的行为（即默认时）比较模糊，所以我们现在清晰地把作用域指明出来，总共有3种类型的作用：\n * 分别是 ProjectScope、UserScope 和 SystemScope，分别对应项目级、用户级和系统级的换源配置\n *\n * 还有一个叫 ImplementationDefinedScope 的作用域，它不是一种新类型，而是表示根据实际情况决定的作用域。\n * chsrc 将根据该 target 的实际情况来选择最合适的作用域来进行换源配置。最好的情况下，ImplementationDefinedScope 是三者之一，\n * 这也是这里设计的初衷。然而现在有些 recipe 的换源行为，会在某种 Scope 不能够成功时退而求其次地使用另一个 Scope\n * 来进行换源配置，这时就只能用 ImplementationDefinedScope 来表示。\n */\n#define NumberOfScopeType    3\n typedef enum Scope_t\n{\n  ProjectScope,\n  UserScope,\n  SystemScope,\n\n  /**\n   * 这是 target 默认的作用域，一种特殊的作用域，即根据 target 的实际情况来决定的。\n   * 它不是一种真正的类型，因为最终换源后，用户看到的作用域依然是 ProjectScope、UserScope 或 SystemScope 中的一个\n   */\n  ImplementationDefinedScope,\n}\nScope_t;\n\n#define ScopeCap_Slot_Project 0\n#define ScopeCap_Slot_User    1\n#define ScopeCap_Slot_System  2\n\ntypedef enum ScopeCapability_t\n{\n  ScopeCap_Unknown,                  /* 未知，缺乏对该 target 的细致了解 */\n  ScopeCap_Unable,                   /* 不支持该作用域 */\n  ScopeCap_Able_But_Not_Implemented, /* 支持但chsrc尚未实现 */\n  ScopeCap_Able_And_Implemented      /* 支持且chsrc已经实现 */\n}\nScopeCapability_t;\n\ntypedef enum Capability_t\n{\n  CanNot,\n  FullyCan,\n  PartiallyCan\n}\nCapability_t;\n\n\n\ntypedef struct Contributor_t\n{\n  char *id;     /* 全局唯一贡献者标识符，防止反复写信息，以 @ 开头 */\n  char *name;   /* 贡献者姓名; 鉴于该项目完全依赖于贡献者，建议留下真实姓名或者昵称 */\n  char *email;\n  char *display_name; /* recipe 结束时会显示贡献者信息，如果你不愿显示真实姓名或者昵称，可以另外提供一个名字 */\n}\nContributor_t;\n\n\ntypedef struct Target_t\n{\n  /* 以 / 为分隔符的多个目标别名 */\n  char *aliases;\n\n  void (*getfn)   (char *option);\n  void (*setfn)   (char *option);\n  void (*resetfn) (char *option);\n\n  /* 初始化函数，用于填充该 struct 的各种信息 */\n  void (*preludefn) (void);\n  bool inited; /* 是否执行过了 preludefn() */\n\n  Source_t *sources;\n       int  sources_n;\n\n\n  /* Features */\n  bool  can_english;        /* 是否支持英文输出 */\n\n  bool  can_user_define;    /* 是否支持用户自定义URL来换源 */\n  char *can_user_define_explain; /* 用户自定义URL的说明 */\n\n  /**\n   * 各作用域的支持情况\n   * 参考 ScopeCap_Slot_Xxx 的值\n   */\n  ScopeCapability_t scope_caps[NumberOfScopeType];\n  Scope_t default_scope;   /* 默认作用域 */\n\n  char *note;              /* 备注 */\n\n\n  /* recipe 维护信息 */\n  char *created_on;\n  char *last_updated;\n  char *sources_last_updated;\n\n  Contributor_t  *chef;     /* 该 recipe *当前*的总负责人 (可以任职也可以休职) */\n  Contributor_t **cooks;    /* 该 recipe 的主要作者 */\n            int   cooks_n;\n  Contributor_t **sauciers; /* 该 recipe 的次要贡献者 (除主要作者外的其他人) */\n            int   sauciers_n;\n}\nTarget_t;\n\n\n\n#define def_target(t, aliases) void t##_getsrc(char *option);void t##_setsrc(char *option);void t##_resetsrc(char *option); Target_t t##_target={aliases};\n\n#define chef_allow_gsr(t) this->getfn = t##_getsrc; this->setfn = t##_setsrc; this->resetfn = t##_resetsrc;\n#define chef_allow_s(t)   this->getfn = NULL;       this->setfn = t##_setsrc; this->resetfn = NULL;\n#define chef_allow_sr(t)  this->getfn = NULL;       this->setfn = t##_setsrc; this->resetfn = t##_resetsrc;\n#define chef_allow_gs(t)  this->getfn = t##_getsrc; this->setfn = t##_setsrc; this->resetfn = NULL;\n#define chef_allow_NOOP(t)\n#define chef_prep_this(t,op) Target_t *this = &t##_target; this->inited = true; chef_allow_##op(t);\n\n#define chef_use_this(t) Target_t *this = &t##_target;\n#define chsrc_use_this_source(t) Target_t *this = &t##_target; Source_t source = chsrc_yield_source_and_confirm (this, option);\n\n/**\n * 用于定义换源列表\n *\n *   def_sources_begin()\n *   {&UpstreamProvider, \"换源URL\", \"精准测速链接\"},\n *   {&某镜像站1,        \"换源URL\", \"精准测速链接\"},\n *   {&某镜像站2,        \"换源URL\",  NULL },  // 若精准测速链接为空，则为模糊测速，默认使用该镜像站的整体测速链接\n *   def_sources_end()\n *\n *   出于代码美观考虑，上述第三列可以写 FeedByPrelude，然后下面使用文档 ./doc/11-如何设置换源链接与测速链接.md 中的函数来填充\n */\n#define def_sources_begin()  Source_t sources[] = {\n#define def_sources_end()    }; \\\n  this->sources_n = xy_c_array_len(sources); \\\n  char *_sources_storage = xy_malloc0 (sizeof(sources)); \\\n  memcpy (_sources_storage, sources, sizeof(sources)); \\\n  this->sources = (Source_t *)_sources_storage;\n"
  },
  {
    "path": "src/framework/version.h",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Name     : version.h\n * File Authors  : @ccmywish\n *               | @Mikachu2333\n * Contributors  : Nil Null <nil@null.org>\n *               |\n * Created On    : <2025-10-10>\n * Last Modified : <See 'Chsrc_Release_Date'>\n *\n * 发布新版本前请修改此文件\n * ------------------------------------------------------------*/\n\n#define Chsrc_Version        \"0.2.5-alpha1\"\n// 以下四个宏仅用于 resource/chsrc.rc\n#define Chsrc_Version_Major  0\n#define Chsrc_Version_Minor  2\n#define Chsrc_Version_Patch  5\n#define Chsrc_Version_Pre    0\n\n#define Chsrc_Release_Date   \"2026/02/24\"\n"
  },
  {
    "path": "src/rawstr4c.h",
    "content": "#pragma once\n\n/**\n * Generated by rawstr4c v1.1.0-2025/09/27\n */\n\nchar RAWSTR_chsrc_USAGE_CHINESE[] = \"\\345\\220\\215\\347\\247\\260\\072\\012\\040\\040\\040\\143\\150\\163\\162\\143\\040\\055\\040\\103\\150\\141\\156\\147\\145\\040\\123\\157\\165\\162\\143\\145\\040\\055\\040\\050\\107\\120\\114\\166\\063\\053\\051\\012\\012\\347\\211\\210\\346\\234\\254\\072\\012\\040\\040\\040\\100\\166\\145\\162\\100\\012\\012\\344\\275\\277\\347\\224\\250\\072\\012\\040\\040\\040\\143\\150\\163\\162\\143\\040\\074\\143\\157\\155\\155\\141\\156\\144\\076\\040\\133\\157\\160\\164\\151\\157\\156\\163\\135\\040\\133\\164\\141\\162\\147\\145\\164\\135\\040\\133\\155\\151\\162\\162\\157\\162\\135\\012\\012\\345\\221\\275\\344\\273\\244\\072\\012\\040\\040\\040\\150\\145\\154\\160\\054\\040\\040\\150\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\346\\211\\223\\345\\215\\260\\346\\255\\244\\345\\270\\256\\345\\212\\251\\357\\274\\214\\346\\210\\226\\040\\055\\150\\054\\040\\055\\055\\150\\145\\154\\160\\012\\040\\040\\040\\151\\163\\163\\165\\145\\054\\040\\151\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\346\\237\\245\\347\\234\\213\\347\\233\\270\\345\\205\\263\\151\\163\\163\\165\\145\\012\\012\\040\\040\\040\\154\\151\\163\\164\\054\\040\\154\\163\\054\\040\\154\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\345\\210\\227\\345\\207\\272\\345\\217\\257\\347\\224\\250\\351\\225\\234\\345\\203\\217\\347\\253\\231\\345\\222\\214\\345\\217\\257\\346\\215\\242\\346\\272\\220\\347\\233\\256\\346\\240\\207\\012\\040\\040\\040\\154\\151\\163\\164\\040\\040\\155\\151\\162\\162\\157\\162\\174\\164\\141\\162\\147\\145\\164\\040\\040\\040\\040\\040\\040\\040\\040\\345\\210\\227\\345\\207\\272\\346\\224\\257\\346\\214\\201\\347\\232\\204\\072\\040\\351\\225\\234\\345\\203\\217\\347\\253\\231\\057\\346\\215\\242\\346\\272\\220\\347\\233\\256\\346\\240\\207\\012\\040\\040\\040\\154\\151\\163\\164\\040\\040\\157\\163\\174\\154\\141\\156\\147\\174\\167\\141\\162\\145\\040\\040\\040\\040\\040\\040\\040\\040\\040\\345\\210\\227\\345\\207\\272\\346\\224\\257\\346\\214\\201\\347\\232\\204\\072\\040\\346\\223\\215\\344\\275\\234\\347\\263\\273\\347\\273\\237\\057\\347\\274\\226\\347\\250\\213\\350\\257\\255\\350\\250\\200\\057\\350\\275\\257\\344\\273\\266\\012\\040\\040\\040\\154\\151\\163\\164\\040\\040\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\346\\237\\245\\347\\234\\213\\350\\257\\245\\347\\233\\256\\346\\240\\207\\345\\217\\257\\347\\224\\250\\346\\272\\220\\344\\270\\216\\346\\224\\257\\346\\214\\201\\345\\212\\237\\350\\203\\275\\012\\012\\040\\040\\040\\155\\145\\141\\163\\165\\162\\145\\054\\040\\155\\054\\040\\143\\145\\163\\165\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\345\\257\\271\\350\\257\\245\\347\\233\\256\\346\\240\\207\\346\\211\\200\\346\\234\\211\\346\\272\\220\\346\\265\\213\\351\\200\\237\\012\\012\\040\\040\\040\\147\\145\\164\\054\\040\\147\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\346\\237\\245\\347\\234\\213\\350\\257\\245\\347\\233\\256\\346\\240\\207\\345\\275\\223\\345\\211\\215\\346\\272\\220\\347\\232\\204\\344\\275\\277\\347\\224\\250\\346\\203\\205\\345\\206\\265\\012\\012\\040\\040\\040\\163\\145\\164\\054\\040\\163\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\346\\215\\242\\346\\272\\220\\357\\274\\214\\350\\207\\252\\345\\212\\250\\346\\265\\213\\351\\200\\237\\345\\220\\216\\346\\214\\221\\351\\200\\211\\346\\234\\200\\345\\277\\253\\346\\272\\220\\012\\040\\040\\040\\163\\145\\164\\040\\040\\040\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\146\\151\\162\\163\\164\\040\\040\\040\\040\\040\\346\\215\\242\\346\\272\\220\\357\\274\\214\\344\\275\\277\\347\\224\\250\\347\\273\\264\\346\\212\\244\\345\\233\\242\\351\\230\\237\\346\\265\\213\\351\\200\\237\\347\\254\\254\\344\\270\\200\\347\\232\\204\\346\\272\\220\\012\\040\\040\\040\\163\\145\\164\\040\\040\\040\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\074\\155\\151\\162\\162\\157\\162\\076\\040\\040\\040\\346\\215\\242\\346\\272\\220\\357\\274\\214\\346\\214\\207\\345\\256\\232\\344\\275\\277\\347\\224\\250\\346\\237\\220\\351\\225\\234\\345\\203\\217\\347\\253\\231\\040\\050\\351\\200\\232\\350\\277\\207\\154\\151\\163\\164\\040\\074\\164\\141\\162\\147\\145\\164\\076\\346\\237\\245\\347\\234\\213\\051\\012\\040\\040\\040\\163\\145\\164\\040\\040\\040\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\074\\125\\122\\114\\076\\040\\040\\040\\040\\040\\346\\215\\242\\346\\272\\220\\357\\274\\214\\347\\224\\250\\346\\210\\267\\350\\207\\252\\345\\256\\232\\344\\271\\211\\346\\272\\220\\125\\122\\114\\012\\040\\040\\040\\162\\145\\163\\145\\164\\040\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\351\\207\\215\\347\\275\\256\\357\\274\\214\\344\\275\\277\\347\\224\\250\\344\\270\\212\\346\\270\\270\\351\\273\\230\\350\\256\\244\\344\\275\\277\\347\\224\\250\\347\\232\\204\\346\\272\\220\\012\\012\\351\\200\\211\\351\\241\\271\\072\\012\\040\\040\\040\\055\\144\\162\\171\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\104\\162\\171\\040\\122\\165\\156\\357\\274\\214\\346\\250\\241\\346\\213\\237\\346\\215\\242\\346\\272\\220\\350\\277\\207\\347\\250\\213\\357\\274\\214\\345\\221\\275\\344\\273\\244\\344\\273\\205\\346\\211\\223\\345\\215\\260\\345\\271\\266\\344\\270\\215\\350\\277\\220\\350\\241\\214\\012\\040\\040\\040\\055\\163\\143\\157\\160\\145\\075\\160\\162\\157\\152\\145\\143\\164\\174\\165\\163\\145\\162\\174\\163\\171\\163\\164\\145\\155\\040\\344\\273\\205\\345\\257\\271\\346\\234\\254\\351\\241\\271\\347\\233\\256\\346\\215\\242\\346\\272\\220\\040\\057\\040\\347\\224\\250\\346\\210\\267\\347\\272\\247\\346\\215\\242\\346\\272\\220\\040\\057\\040\\347\\263\\273\\347\\273\\237\\347\\272\\247\\346\\215\\242\\346\\272\\220\\040\\050\\351\\200\\232\\350\\277\\207\\154\\163\\040\\074\\164\\141\\162\\147\\145\\164\\076\\346\\237\\245\\347\\234\\213\\051\\012\\040\\040\\040\\055\\151\\160\\166\\066\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\344\\275\\277\\347\\224\\250\\111\\120\\166\\066\\346\\265\\213\\351\\200\\237\\012\\040\\040\\040\\055\\145\\156\\050\\147\\154\\151\\163\\150\\051\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\344\\275\\277\\347\\224\\250\\350\\213\\261\\346\\226\\207\\350\\276\\223\\345\\207\\272\\012\\040\\040\\040\\055\\156\\157\\055\\143\\157\\154\\157\\162\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\346\\227\\240\\351\\242\\234\\350\\211\\262\\350\\276\\223\\345\\207\\272\\012\\012\\347\\273\\264\\346\\212\\244\\072\\012\\040\\040\\040\\351\\202\\200\\350\\257\\267\\346\\202\\250\\346\\213\\205\\344\\273\\273\\040\\040\\103\\150\\145\\146\\054\\040\\344\\270\\272\\347\\224\\250\\346\\210\\267\\346\\212\\212\\345\\205\\263\\346\\202\\250\\347\\206\\237\\346\\202\\211\\347\\232\\204\\040\\162\\145\\143\\151\\160\\145\\012\\012\\040\\040\\040\\346\\272\\220\\344\\273\\243\\347\\240\\201\\345\\234\\260\\345\\235\\200\\072\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\150\\165\\142\\056\\143\\157\\155\\057\\122\\165\\142\\171\\115\\145\\164\\162\\151\\143\\057\\143\\150\\163\\162\\143\\012\\040\\040\\040\\346\\210\\220\\344\\270\\272\\347\\273\\264\\346\\212\\244\\350\\200\\205\\072\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\150\\165\\142\\056\\143\\157\\155\\057\\122\\165\\142\\171\\115\\145\\164\\162\\151\\143\\057\\143\\150\\163\\162\\143\\057\\151\\163\\163\\165\\145\\163\\057\\062\\067\\065\";\n\nchar RAWSTR_chsrc_USAGE_ENGLISH[] = \"\\116\\101\\115\\105\\072\\012\\040\\040\\040\\143\\150\\163\\162\\143\\040\\055\\040\\103\\150\\141\\156\\147\\145\\040\\123\\157\\165\\162\\143\\145\\040\\055\\040\\050\\107\\120\\114\\166\\063\\053\\051\\012\\012\\126\\105\\122\\123\\111\\117\\116\\072\\012\\040\\040\\040\\100\\166\\145\\162\\100\\012\\012\\125\\123\\101\\107\\105\\072\\012\\040\\040\\040\\143\\150\\163\\162\\143\\040\\074\\143\\157\\155\\155\\141\\156\\144\\076\\040\\133\\157\\160\\164\\151\\157\\156\\163\\135\\040\\133\\164\\141\\162\\147\\145\\164\\135\\040\\133\\155\\151\\162\\162\\157\\162\\135\\012\\012\\103\\117\\115\\115\\101\\116\\104\\123\\072\\012\\040\\040\\040\\150\\145\\154\\160\\054\\040\\040\\150\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\120\\162\\151\\156\\164\\040\\164\\150\\151\\163\\040\\150\\145\\154\\160\\054\\040\\157\\162\\040\\055\\150\\054\\040\\055\\055\\150\\145\\154\\160\\012\\040\\040\\040\\151\\163\\163\\165\\145\\054\\040\\151\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\123\\145\\145\\040\\162\\145\\154\\141\\164\\145\\144\\040\\151\\163\\163\\165\\145\\163\\012\\012\\040\\040\\040\\154\\151\\163\\164\\054\\040\\154\\163\\054\\040\\154\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\114\\151\\163\\164\\040\\141\\166\\141\\151\\154\\141\\142\\154\\145\\040\\155\\151\\162\\162\\157\\162\\040\\163\\151\\164\\145\\163\\040\\141\\156\\144\\040\\163\\165\\160\\160\\157\\162\\164\\145\\144\\040\\164\\141\\162\\147\\145\\164\\163\\012\\040\\040\\040\\154\\151\\163\\164\\040\\040\\155\\151\\162\\162\\157\\162\\174\\164\\141\\162\\147\\145\\164\\040\\040\\040\\040\\040\\040\\040\\040\\114\\151\\163\\164\\040\\163\\165\\160\\160\\157\\162\\164\\145\\144\\072\\040\\040\\155\\151\\162\\162\\157\\162\\040\\163\\151\\164\\145\\163\\057\\163\\165\\160\\160\\157\\162\\164\\145\\144\\040\\164\\141\\162\\147\\145\\164\\163\\012\\040\\040\\040\\154\\151\\163\\164\\040\\040\\157\\163\\174\\154\\141\\156\\147\\174\\167\\141\\162\\145\\040\\040\\040\\040\\040\\040\\040\\040\\040\\114\\151\\163\\164\\040\\163\\165\\160\\160\\157\\162\\164\\145\\144\\072\\040\\117\\123\\145\\163\\057\\120\\162\\157\\147\\162\\141\\155\\155\\151\\156\\147\\040\\114\\141\\156\\147\\165\\141\\147\\145\\163\\057\\123\\157\\146\\164\\167\\141\\162\\145\\163\\012\\040\\040\\040\\154\\151\\163\\164\\040\\040\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\126\\151\\145\\167\\040\\141\\166\\141\\151\\154\\141\\142\\154\\145\\040\\163\\157\\165\\162\\143\\145\\163\\040\\141\\156\\144\\040\\163\\165\\160\\160\\157\\162\\164\\151\\156\\147\\040\\146\\145\\141\\164\\165\\162\\145\\163\\040\\146\\157\\162\\040\\074\\164\\141\\162\\147\\145\\164\\076\\012\\012\\040\\040\\040\\155\\145\\141\\163\\165\\162\\145\\054\\040\\155\\054\\040\\143\\145\\163\\165\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\115\\145\\141\\163\\165\\162\\145\\040\\166\\145\\154\\157\\143\\151\\164\\171\\040\\157\\146\\040\\141\\154\\154\\040\\163\\157\\165\\162\\143\\145\\163\\040\\157\\146\\040\\074\\164\\141\\162\\147\\145\\164\\076\\012\\012\\040\\040\\040\\147\\145\\164\\054\\040\\147\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\126\\151\\145\\167\\040\\164\\150\\145\\040\\143\\165\\162\\162\\145\\156\\164\\040\\163\\157\\165\\162\\143\\145\\040\\163\\164\\141\\164\\145\\040\\146\\157\\162\\040\\074\\164\\141\\162\\147\\145\\164\\076\\012\\012\\040\\040\\040\\163\\145\\164\\054\\040\\163\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\103\\150\\141\\156\\147\\145\\040\\163\\157\\165\\162\\143\\145\\054\\040\\163\\145\\154\\145\\143\\164\\040\\164\\150\\145\\040\\146\\141\\163\\164\\145\\163\\164\\040\\163\\157\\165\\162\\143\\145\\040\\142\\171\\040\\141\\165\\164\\157\\155\\141\\164\\151\\143\\040\\163\\160\\145\\145\\144\\040\\155\\145\\141\\163\\165\\162\\145\\155\\145\\156\\164\\012\\040\\040\\040\\163\\145\\164\\040\\040\\040\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\146\\151\\162\\163\\164\\040\\040\\040\\040\\040\\103\\150\\141\\156\\147\\145\\040\\163\\157\\165\\162\\143\\145\\054\\040\\163\\145\\154\\145\\143\\164\\040\\164\\150\\145\\040\\146\\141\\163\\164\\145\\163\\164\\040\\163\\157\\165\\162\\143\\145\\040\\155\\145\\141\\163\\165\\162\\145\\144\\040\\142\\171\\040\\164\\150\\145\\040\\155\\141\\151\\156\\164\\141\\151\\156\\145\\162\\163\\040\\164\\145\\141\\155\\012\\040\\040\\040\\163\\145\\164\\040\\040\\040\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\074\\155\\151\\162\\162\\157\\162\\076\\040\\040\\040\\103\\150\\141\\156\\147\\145\\040\\163\\157\\165\\162\\143\\145\\054\\040\\163\\160\\145\\143\\151\\146\\171\\040\\141\\040\\155\\151\\162\\162\\157\\162\\040\\163\\151\\164\\145\\040\\050\\126\\151\\141\\040\\140\\154\\151\\163\\164\\040\\074\\164\\141\\162\\147\\145\\164\\076\\140\\051\\012\\040\\040\\040\\163\\145\\164\\040\\040\\040\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\074\\125\\122\\114\\076\\040\\040\\040\\040\\040\\103\\150\\141\\156\\147\\145\\040\\163\\157\\165\\162\\143\\145\\054\\040\\165\\163\\151\\156\\147\\040\\165\\163\\145\\162\\055\\144\\145\\146\\151\\156\\145\\144\\040\\163\\157\\165\\162\\143\\145\\040\\125\\122\\114\\012\\040\\040\\040\\162\\145\\163\\145\\164\\040\\040\\074\\164\\141\\162\\147\\145\\164\\076\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\122\\145\\163\\145\\164\\040\\040\\163\\157\\165\\162\\143\\145\\040\\164\\157\\040\\164\\150\\145\\040\\165\\160\\163\\164\\162\\145\\141\\155\\047\\163\\040\\144\\145\\146\\141\\165\\154\\164\\012\\012\\117\\120\\124\\111\\117\\116\\123\\072\\012\\040\\040\\040\\055\\144\\162\\171\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\104\\162\\171\\040\\122\\165\\156\\056\\040\\123\\151\\155\\165\\154\\141\\164\\145\\040\\164\\150\\145\\040\\163\\157\\165\\162\\143\\145\\040\\143\\150\\141\\156\\147\\151\\156\\147\\040\\160\\162\\157\\143\\145\\163\\163\\054\\040\\143\\157\\155\\155\\141\\156\\144\\040\\157\\156\\154\\171\\040\\160\\162\\151\\156\\164\\163\\054\\040\\156\\157\\164\\040\\162\\165\\156\\012\\040\\040\\040\\055\\163\\143\\157\\160\\145\\075\\160\\162\\157\\152\\145\\143\\164\\174\\165\\163\\145\\162\\174\\163\\171\\163\\164\\145\\155\\040\\103\\150\\141\\156\\147\\145\\040\\163\\157\\165\\162\\143\\145\\040\\157\\156\\154\\171\\040\\146\\157\\162\\040\\164\\150\\151\\163\\040\\160\\162\\157\\152\\145\\143\\164\\040\\057\\040\\165\\163\\145\\162\\040\\154\\145\\166\\145\\154\\040\\057\\040\\163\\171\\163\\164\\145\\155\\040\\154\\145\\166\\145\\154\\040\\050\\126\\151\\141\\040\\140\\154\\163\\040\\074\\164\\141\\162\\147\\145\\164\\076\\140\\051\\012\\040\\040\\040\\055\\151\\160\\166\\066\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\123\\160\\145\\145\\144\\040\\155\\145\\141\\163\\165\\162\\145\\155\\145\\156\\164\\040\\165\\163\\151\\156\\147\\040\\111\\120\\166\\066\\012\\040\\040\\040\\055\\145\\156\\050\\147\\154\\151\\163\\150\\051\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\117\\165\\164\\160\\165\\164\\040\\151\\156\\040\\105\\156\\147\\154\\151\\163\\150\\012\\040\\040\\040\\055\\156\\157\\055\\143\\157\\154\\157\\162\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\117\\165\\164\\160\\165\\164\\040\\167\\151\\164\\150\\157\\165\\164\\040\\143\\157\\154\\157\\162\\012\\012\\115\\101\\111\\116\\124\\101\\111\\116\\072\\012\\040\\040\\040\\127\\145\\040\\151\\156\\166\\151\\164\\145\\040\\171\\157\\165\\040\\164\\157\\040\\142\\145\\143\\157\\155\\145\\040\\141\\040\\103\\150\\145\\146\\040\\164\\157\\040\\145\\156\\163\\165\\162\\145\\040\\164\\150\\145\\040\\161\\165\\141\\154\\151\\164\\171\\040\\157\\146\\040\\162\\145\\143\\151\\160\\145\\163\\040\\171\\157\\165\\040\\141\\162\\145\\040\\146\\141\\155\\151\\154\\151\\141\\162\\040\\167\\151\\164\\150\\040\\146\\157\\162\\040\\165\\163\\145\\162\\163\\072\\012\\012\\040\\040\\040\\123\\157\\165\\162\\143\\145\\040\\103\\157\\144\\145\\072\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\150\\165\\142\\056\\143\\157\\155\\057\\122\\165\\142\\171\\115\\145\\164\\162\\151\\143\\057\\143\\150\\163\\162\\143\\012\\040\\040\\040\\102\\145\\143\\157\\155\\145\\040\\141\\040\\115\\141\\151\\156\\164\\141\\151\\156\\145\\162\\072\\040\\040\\040\\040\\040\\040\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\150\\165\\142\\056\\143\\157\\155\\057\\122\\165\\142\\171\\115\\145\\164\\162\\151\\143\\057\\143\\150\\163\\162\\143\\057\\151\\163\\163\\165\\145\\163\\057\\062\\067\\065\";\n\nchar RAWSTR_chsrc_for_v_CHINESE[] = \"\\143\\150\\163\\162\\143\\040\\100\\166\\145\\162\\100\\012\\012\\103\\157\\160\\171\\162\\151\\147\\150\\164\\040\\050\\103\\051\\040\\062\\060\\062\\063\\055\\062\\060\\062\\066\\040\\346\\233\\276\\345\\245\\245\\347\\204\\266\\054\\040\\351\\203\\255\\346\\201\\222\\012\\350\\256\\270\\345\\217\\257\\350\\257\\201\\040\\107\\120\\114\\166\\063\\053\\357\\274\\232\\107\\116\\125\\040\\107\\120\\114\\040\\347\\254\\254\\040\\063\\040\\347\\211\\210\\346\\210\\226\\346\\233\\264\\351\\253\\230\\347\\211\\210\\346\\234\\254\\040\\074\\150\\164\\164\\160\\163\\072\\057\\057\\147\\156\\165\\056\\157\\162\\147\\057\\154\\151\\143\\145\\156\\163\\145\\163\\057\\147\\160\\154\\056\\150\\164\\155\\154\\076\\012\\350\\277\\231\\346\\230\\257\\350\\207\\252\\347\\224\\261\\350\\275\\257\\344\\273\\266\\357\\274\\232\\346\\202\\250\\345\\217\\257\\344\\273\\245\\350\\207\\252\\347\\224\\261\\344\\277\\256\\346\\224\\271\\345\\222\\214\\345\\210\\206\\345\\217\\221\\345\\256\\203\\343\\200\\202\\012\\345\\234\\250\\346\\263\\225\\345\\276\\213\\345\\205\\201\\350\\256\\270\\347\\232\\204\\346\\234\\200\\345\\244\\247\\350\\214\\203\\345\\233\\264\\345\\206\\205\\357\\274\\214\\346\\234\\254\\350\\275\\257\\344\\273\\266\\346\\214\\211\\047\\345\\216\\237\\346\\240\\267\\047\\346\\217\\220\\344\\276\\233\\357\\274\\214\\344\\270\\215\\344\\275\\234\\344\\273\\273\\344\\275\\225\\346\\230\\216\\347\\244\\272\\346\\210\\226\\346\\232\\227\\347\\244\\272\\347\\232\\204\\344\\277\\235\\350\\257\\201\\343\\200\\202\\012\\012\\347\\224\\261\\344\\275\\234\\350\\200\\205\\357\\274\\232\\346\\233\\276\\345\\245\\245\\347\\204\\266\\343\\200\\201\\351\\203\\255\\346\\201\\222\\357\\274\\214\\345\\215\\217\\344\\275\\234\\350\\200\\205\\357\\274\\232\\115\\151\\153\\141\\143\\150\\165\\062\\063\\063\\063\\343\\200\\201\\110\\141\\160\\160\\171\\040\\107\\141\\155\\145\\040\\344\\273\\245\\345\\217\\212\\345\\220\\204\\344\\275\\215\\350\\264\\241\\347\\214\\256\\350\\200\\205\\345\\274\\200\\345\\217\\221\\343\\200\\202\\050\\350\\257\\246\\350\\247\\201\\040\\143\\150\\163\\162\\143\\055\\155\\141\\151\\156\\056\\143\\054\\040\\346\\210\\226\\040\\140\\143\\150\\163\\162\\143\\040\\154\\163\\040\\074\\164\\141\\162\\147\\145\\164\\076\\140\\051\";\n\nchar RAWSTR_chsrc_for_v_ENGLISH[] = \"\\143\\150\\163\\162\\143\\040\\100\\166\\145\\162\\100\\012\\012\\103\\157\\160\\171\\162\\151\\147\\150\\164\\040\\050\\103\\051\\040\\062\\060\\062\\063\\055\\062\\060\\062\\066\\040\\101\\157\\162\\141\\156\\040\\132\\145\\156\\147\\054\\040\\110\\145\\156\\147\\040\\107\\165\\157\\012\\114\\151\\143\\145\\156\\163\\145\\040\\107\\120\\114\\166\\063\\053\\072\\040\\107\\116\\125\\040\\107\\120\\114\\040\\166\\145\\162\\163\\151\\157\\156\\040\\063\\040\\157\\162\\040\\154\\141\\164\\145\\162\\040\\074\\150\\164\\164\\160\\163\\072\\057\\057\\147\\156\\165\\056\\157\\162\\147\\057\\154\\151\\143\\145\\156\\163\\145\\163\\057\\147\\160\\154\\056\\150\\164\\155\\154\\076\\012\\124\\150\\151\\163\\040\\151\\163\\040\\146\\162\\145\\145\\040\\163\\157\\146\\164\\167\\141\\162\\145\\072\\040\\171\\157\\165\\040\\141\\162\\145\\040\\146\\162\\145\\145\\040\\164\\157\\040\\143\\150\\141\\156\\147\\145\\040\\141\\156\\144\\040\\162\\145\\144\\151\\163\\164\\162\\151\\142\\165\\164\\145\\040\\151\\164\\056\\012\\124\\150\\145\\162\\145\\040\\151\\163\\040\\116\\117\\040\\127\\101\\122\\122\\101\\116\\124\\131\\054\\040\\164\\157\\040\\164\\150\\145\\040\\145\\170\\164\\145\\156\\164\\040\\160\\145\\162\\155\\151\\164\\164\\145\\144\\040\\142\\171\\040\\154\\141\\167\\056\\012\\012\\127\\162\\151\\164\\164\\145\\156\\040\\142\\171\\040\\141\\165\\164\\150\\157\\162\\163\\072\\040\\101\\157\\162\\141\\156\\040\\132\\145\\156\\147\\054\\040\\110\\145\\156\\147\\040\\107\\165\\157\\054\\040\\143\\157\\154\\154\\141\\142\\157\\162\\141\\164\\157\\162\\163\\072\\040\\115\\151\\153\\141\\143\\150\\165\\062\\063\\063\\063\\054\\040\\110\\141\\160\\160\\171\\040\\107\\141\\155\\145\\054\\040\\141\\156\\144\\040\\143\\157\\156\\164\\162\\151\\142\\165\\164\\157\\162\\163\\056\\040\\050\\123\\145\\145\\040\\143\\150\\163\\162\\143\\055\\155\\141\\151\\156\\056\\143\\054\\040\\157\\162\\040\\140\\143\\150\\163\\162\\143\\040\\154\\163\\040\\074\\164\\141\\162\\147\\145\\164\\076\\140\\051\";\n\nchar RAWSTR_chsrc_for_issue[] = \"\\346\\210\\221\\344\\273\\254\\345\\220\\214\\346\\227\\266\\345\\234\\250\\040\\107\\151\\164\\110\\165\\142\\040\\345\\222\\214\\040\\107\\151\\164\\145\\145\\040\\346\\216\\245\\345\\217\\227\\040\\151\\163\\163\\165\\145\\040\\345\\222\\214\\040\\102\\165\\147\\040\\346\\212\\245\\345\\221\\212\\072\\012\\012\\040\\040\\055\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\150\\165\\142\\056\\143\\157\\155\\057\\122\\165\\142\\171\\115\\145\\164\\162\\151\\143\\057\\143\\150\\163\\162\\143\\057\\151\\163\\163\\165\\145\\163\\012\\040\\040\\055\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\145\\145\\056\\143\\157\\155\\057\\122\\165\\142\\171\\115\\145\\164\\162\\151\\143\\057\\143\\150\\163\\162\\143\\057\\151\\163\\163\\165\\145\\163\\012\\012\\012\\346\\254\\242\\350\\277\\216\\345\\217\\202\\344\\270\\216\\345\\205\\267\\344\\275\\223\\344\\273\\273\\345\\212\\241\\072\\012\\012\\040\\040\\040\\123\\150\\145\\154\\154\\040\\141\\165\\164\\157\\055\\143\\157\\155\\160\\154\\145\\164\\151\\157\\156\\040\\347\\273\\210\\347\\253\\257\\345\\221\\275\\344\\273\\244\\350\\207\\252\\345\\212\\250\\350\\241\\245\\345\\205\\250\\072\\012\\012\\040\\040\\040\\040\\040\\040\\040\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\150\\165\\142\\056\\143\\157\\155\\057\\122\\165\\142\\171\\115\\145\\164\\162\\151\\143\\057\\143\\150\\163\\162\\143\\057\\151\\163\\163\\165\\145\\163\\057\\062\\060\\064\\012\\012\\040\\040\\040\\346\\220\\234\\351\\233\\206\\344\\270\\212\\346\\270\\270\\351\\273\\230\\350\\256\\244\\346\\272\\220\\345\\234\\260\\345\\235\\200\\357\\274\\214\\345\\270\\256\\345\\212\\251\\350\\277\\233\\350\\241\\214\\040\\143\\150\\163\\162\\143\\040\\162\\145\\163\\145\\164\\072\\012\\012\\040\\040\\040\\040\\040\\040\\040\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\150\\165\\142\\056\\143\\157\\155\\057\\122\\165\\142\\171\\115\\145\\164\\162\\151\\143\\057\\143\\150\\163\\162\\143\\057\\151\\163\\163\\165\\145\\163\\057\\061\\061\\061\\012\\012\\040\\040\\040\\346\\220\\234\\351\\233\\206\\346\\265\\213\\351\\200\\237\\345\\234\\260\\345\\235\\200\\357\\274\\214\\350\\277\\233\\350\\241\\214\\347\\262\\276\\345\\207\\206\\346\\265\\213\\351\\200\\237\\072\\012\\012\\040\\040\\040\\040\\040\\040\\040\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\150\\165\\142\\056\\143\\157\\155\\057\\122\\165\\142\\171\\115\\145\\164\\162\\151\\143\\057\\143\\150\\163\\162\\143\\057\\151\\163\\163\\165\\145\\163\\057\\062\\060\\065\\012\\012\\040\\040\\040\\345\\270\\256\\345\\212\\251\\346\\262\\241\\346\\234\\211\\351\\242\\204\\347\\274\\226\\350\\257\\221\\347\\232\\204\\345\\271\\263\\345\\217\\260\\347\\274\\226\\345\\206\\231\\040\\163\\150\\145\\154\\154\\040\\350\\204\\232\\346\\234\\254\\072\\012\\012\\040\\040\\040\\040\\040\\040\\040\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\150\\165\\142\\056\\143\\157\\155\\057\\122\\165\\142\\171\\115\\145\\164\\162\\151\\143\\057\\143\\150\\163\\162\\143\\057\\151\\163\\163\\165\\145\\163\\057\\062\\063\\060\\012\\012\\012\\346\\224\\257\\346\\214\\201\\347\\232\\204\\351\\200\\232\\347\\224\\250\\351\\225\\234\\345\\203\\217\\347\\253\\231\\072\\012\\040\\040\\055\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\150\\165\\142\\056\\143\\157\\155\\057\\122\\165\\142\\171\\115\\145\\164\\162\\151\\143\\057\\143\\150\\163\\162\\143\\057\\167\\151\\153\\151\\012\";\n\nchar RAWSTR_chsrc_op_epilogue[] = \"\\012\\040\\040\\040\\052\\040\\347\\262\\276\\345\\207\\206\\346\\265\\213\\351\\200\\237\\072\\040\\350\\203\\275\\347\\234\\237\\345\\256\\236\\345\\217\\215\\346\\230\\240\\344\\275\\240\\346\\234\\252\\346\\235\\245\\344\\275\\277\\347\\224\\250\\350\\257\\245\\350\\265\\204\\346\\272\\220\\346\\227\\266\\347\\232\\204\\351\\200\\237\\345\\272\\246\\357\\274\\214\\345\\233\\240\\344\\270\\272\\345\\256\\203\\347\\233\\264\\346\\216\\245\\346\\265\\213\\351\\207\\217\\344\\275\\240\\345\\205\\263\\346\\263\\250\\347\\232\\204\\351\\202\\243\\344\\270\\252\\350\\265\\204\\346\\272\\220\\343\\200\\202\\012\\040\\040\\040\\052\\040\\346\\250\\241\\347\\263\\212\\346\\265\\213\\351\\200\\237\\072\\040\\344\\273\\205\\344\\273\\243\\350\\241\\250\\350\\257\\245\\351\\225\\234\\345\\203\\217\\347\\253\\231\\346\\217\\220\\344\\276\\233\\346\\234\\215\\345\\212\\241\\347\\232\\204\\344\\270\\200\\344\\270\\252\\345\\217\\257\\350\\203\\275\\351\\200\\237\\345\\272\\246\\343\\200\\202\\345\\233\\240\\350\\200\\214\\345\\217\\257\\350\\203\\275\\344\\274\\232\\345\\207\\272\\347\\216\\260\\346\\265\\213\\351\\200\\237\\346\\225\\260\\345\\200\\274\\350\\276\\203\\351\\253\\230\\357\\274\\214\\344\\275\\206\\345\\256\\236\\351\\231\\205\\344\\275\\277\\347\\224\\250\\344\\275\\223\\351\\252\\214\\344\\270\\215\\344\\275\\263\\347\\232\\204\\347\\216\\260\\350\\261\\241\\343\\200\\202\\012\\345\\275\\223\\344\\275\\240\\351\\201\\207\\345\\210\\260\\346\\250\\241\\347\\263\\212\\346\\265\\213\\351\\200\\237\\346\\227\\266\\357\\274\\214\\350\\257\\267\\345\\260\\275\\345\\217\\257\\350\\203\\275\\345\\220\\221\\346\\210\\221\\344\\273\\254\\346\\217\\220\\344\\272\\244\\345\\207\\206\\347\\241\\256\\347\\232\\204\\346\\265\\213\\351\\200\\237\\351\\223\\276\\346\\216\\245\\072\\040\\143\\150\\163\\162\\143\\040\\151\\163\\163\\165\\145\";\n\n"
  },
  {
    "path": "src/rawstr4c.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------------------------------------------------------------\n ! Config Type   : rawstr4c (Markdown)\n ! Config Authors: 曾奥然 <ccmywish@qq.com>\n ! Contributors  : Nil Null <nil@null.org>\n ! Created On    : <2025-07-22>\n ! Last Modified : <2025-10-29>\n ! ---------------------------------------------------------- -->\n\n# [rawstr4c] input for chsrc\n\n`chsrc` 使用的 C标准 (最低要求) 是 `gnu11` (`c11` 的超集)，这也就是说，我们项目是可以，而且是 **推荐** 同时混用 `R\"()\"` 和 `rawstr4c` 的\n\n`LLVM` 对 `R\"()\"` 的支持是在 2024年07月 以后。但是在 GitHub Actions 中，所有出现的 `LLVM` 版本都太低了，\n这使得我们被迫把已经写过的 `R\"()\"` 全部再转换为 `rawstr4c`.\n\n用户端的编译器一般比较新，然而可能也没有新到如此的地步，通过使用 `rawstr4c` 我们也放宽了用户对编译器的要求。\n\n我们预计等2~3年后，在项目中重新开始 `R\"()\"` 的写法\n\n<br>\n\n- prefix = `RAWSTR_chsrc`\n- output = `:global-variable-only-header`\n- translate = `:oct`\n- no-postfix = `true`\n\n<br>\n\n## 中文帮助\n\n- name = `USAGE_CHINESE`\n\n```\n名称:\n   chsrc - Change Source - (GPLv3+)\n\n版本:\n   @ver@\n\n使用:\n   chsrc <command> [options] [target] [mirror]\n\n命令:\n   help,  h                   打印此帮助，或 -h, --help\n   issue, i                   查看相关issue\n\n   list, ls, l                列出可用镜像站和可换源目标\n   list  mirror|target        列出支持的: 镜像站/换源目标\n   list  os|lang|ware         列出支持的: 操作系统/编程语言/软件\n   list   <target>            查看该目标可用源与支持功能\n\n   measure, m, cesu <target>  对该目标所有源测速\n\n   get, g <target>            查看该目标当前源的使用情况\n\n   set, s <target>            换源，自动测速后挑选最快源\n   set    <target>  first     换源，使用维护团队测速第一的源\n   set    <target> <mirror>   换源，指定使用某镜像站 (通过list <target>查看)\n   set    <target>  <URL>     换源，用户自定义源URL\n   reset  <target>            重置，使用上游默认使用的源\n\n选项:\n   -dry                       Dry Run，模拟换源过程，命令仅打印并不运行\n   -scope=project|user|system 仅对本项目换源 / 用户级换源 / 系统级换源 (通过ls <target>查看)\n   -ipv6                      使用IPv6测速\n   -en(glish)                 使用英文输出\n   -no-color                  无颜色输出\n\n维护:\n   邀请您担任  Chef, 为用户把关您熟悉的 recipe\n\n   源代码地址: https://github.com/RubyMetric/chsrc\n   成为维护者: https://github.com/RubyMetric/chsrc/issues/275\n```\n\n<br>\n\n\n\n## 英文帮助\n\n- name = `USAGE_ENGLISH`\n\n```\nNAME:\n   chsrc - Change Source - (GPLv3+)\n\nVERSION:\n   @ver@\n\nUSAGE:\n   chsrc <command> [options] [target] [mirror]\n\nCOMMANDS:\n   help,  h                   Print this help, or -h, --help\n   issue, i                   See related issues\n\n   list, ls, l                List available mirror sites and supported targets\n   list  mirror|target        List supported:  mirror sites/supported targets\n   list  os|lang|ware         List supported: OSes/Programming Languages/Softwares\n   list   <target>            View available sources and supporting features for <target>\n\n   measure, m, cesu <target>  Measure velocity of all sources of <target>\n\n   get, g <target>            View the current source state for <target>\n\n   set, s <target>            Change source, select the fastest source by automatic speed measurement\n   set    <target>  first     Change source, select the fastest source measured by the maintainers team\n   set    <target> <mirror>   Change source, specify a mirror site (Via `list <target>`)\n   set    <target>  <URL>     Change source, using user-defined source URL\n   reset  <target>            Reset  source to the upstream's default\n\nOPTIONS:\n   -dry                       Dry Run. Simulate the source changing process, command only prints, not run\n   -scope=project|user|system Change source only for this project / user level / system level (Via `ls <target>`)\n   -ipv6                      Speed measurement using IPv6\n   -en(glish)                 Output in English\n   -no-color                  Output without color\n\nMAINTAIN:\n   We invite you to become a Chef to ensure the quality of recipes you are familiar with for users:\n\n   Source Code:               https://github.com/RubyMetric/chsrc\n   Become a Maintainer:       https://github.com/RubyMetric/chsrc/issues/275\n```\n\n<br>\n\n\n\n## for `chsrc -v`\n\n- name = `for__v_CHINESE`\n\n```\nchsrc @ver@\n\nCopyright (C) 2023-2026 曾奥然, 郭恒\n许可证 GPLv3+：GNU GPL 第 3 版或更高版本 <https://gnu.org/licenses/gpl.html>\n这是自由软件：您可以自由修改和分发它。\n在法律允许的最大范围内，本软件按'原样'提供，不作任何明示或暗示的保证。\n\n由作者：曾奥然、郭恒，协作者：Mikachu2333、Happy Game 以及各位贡献者开发。(详见 chsrc-main.c, 或 `chsrc ls <target>`)\n```\n\n<br>\n\n\n\n## for `chsrc -v -en`\n\n- name = `for__v_ENGLISH`\n\n```\nchsrc @ver@\n\nCopyright (C) 2023-2026 Aoran Zeng, Heng Guo\nLicense GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n\nWritten by authors: Aoran Zeng, Heng Guo, collaborators: Mikachu2333, Happy Game, and contributors. (See chsrc-main.c, or `chsrc ls <target>`)\n```\n\n<br>\n\n\n\n## for `chsrc issue`\n\n- name = `for_issue`\n\n```\n我们同时在 GitHub 和 Gitee 接受 issue 和 Bug 报告:\n\n  - https://github.com/RubyMetric/chsrc/issues\n  - https://gitee.com/RubyMetric/chsrc/issues\n\n\n欢迎参与具体任务:\n\n   Shell auto-completion 终端命令自动补全:\n\n        https://github.com/RubyMetric/chsrc/issues/204\n\n   搜集上游默认源地址，帮助进行 chsrc reset:\n\n        https://github.com/RubyMetric/chsrc/issues/111\n\n   搜集测速地址，进行精准测速:\n\n        https://github.com/RubyMetric/chsrc/issues/205\n\n   帮助没有预编译的平台编写 shell 脚本:\n\n        https://github.com/RubyMetric/chsrc/issues/230\n\n\n支持的通用镜像站:\n  - https://github.com/RubyMetric/chsrc/wiki\n\n```\n\n<br>\n\n\n\n## 最后告诉用户一些维护信息\n\n- name = `op_epilogue`\n\n```\n\n   * 精准测速: 能真实反映你未来使用该资源时的速度，因为它直接测量你关注的那个资源。\n   * 模糊测速: 仅代表该镜像站提供服务的一个可能速度。因而可能会出现测速数值较高，但实际使用体验不佳的现象。\n当你遇到模糊测速时，请尽可能向我们提交准确的测速链接: chsrc issue\n```\n\n<br>\n\n\n\n[rawstr4c]: https://github.com/RubyMetric/rawstr4c\n"
  },
  {
    "path": "src/recipe/lang/Clojure.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_clojure, \"clojure/clojars/cloj/lein\");\n\nvoid\npl_clojure_prelude ()\n{\n  chef_prep_this (pl_clojure, s);\n\n  chef_set_recipe_created_on   (this, \"2023-09-10\");\n  chef_set_recipe_last_updated (this, \"2026-02-24\");\n  chef_set_sources_last_updated (this, \"2025-08-21\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@hezonglun\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider,\"https://repo.clojars.org/\", DelegateToUpstream},\n  {&MirrorZ,         \"https://mirrors.cernet.edu.cn/clojars/\",        DelegateToMirror},\n  {&Tuna,            \"https://mirrors.tuna.tsinghua.edu.cn/clojars/\", DelegateToMirror},\n  {&Nju,             \"https://mirror.nju.edu.cn/clojars/\",             DelegateToMirror},\n  {&Nyist,           \"https://mirror.nyist.edu.cn/clojars/\",          DelegateToMirror},\n  {&Ustc,            \"https://mirrors.ustc.edu.cn/clojars/\",          DelegateToMirror},\n  {&Iscas,           \"https://mirror.iscas.ac.cn/clojars/\",           DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\npl_clojure_setsrc (char *option)\n{\n  chsrc_use_this_source (pl_clojure);\n\n  if (chsrc_in_project_scope_mode())\n    {\n      chsrc_note2 (\"请在项目根目录中的 project.clj 中手动添加 :mirrors 关键字:\");\n      char *config = xy_str_gsub (RAWSTR_pl_clojure_project_clj, \"@url@\", source.url);\n      println (config);\n    }\n  else\n    {\n      chsrc_note2 (\"请在 ~/.lein/projfiles.clj 中手动添加 :mirrors 关键字:\");\n      char *config = xy_str_gsub (RAWSTR_pl_clojure_projfiles_clj, \"@url@\", source.url);\n      println (config);\n    }\n\n  chsrc_determine_chgtype (ChgType_Manual);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/lang/Dart/Flutter.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_dart_flutter, \"flutter\");\n\nvoid\npl_dart_flutter_prelude (void)\n{\n  chef_prep_this (pl_dart_flutter, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-10\");\n  chef_set_recipe_last_updated (this, \"2025-07-11\");\n  chef_set_sources_last_updated (this, \"2025-04-15\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 2, \"@czyt\", \"@xrgzs\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://storage.googleapis.com\", FeedByPrelude},\n  {&FlutterCN,        \"https://storage.flutter-io.cn\",  FeedByPrelude},\n  {&Sjtug_Zhiyuan,    \"https://mirror.sjtu.edu.cn\",     FeedByPrelude }, /* 官方文档也没有给后缀，怀疑是否存在问题 */\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/flutter\", FeedByPrelude},\n  {&Nju,              \"https://mirror.nju.edu.cn/flutter\", FeedByPrelude}\n  def_sources_end()\n\n  chef_set_rest_smURL_with_postfix (this, \"/flutter_infra_release/releases/stable/linux/flutter_linux_v1.0.0-stable.tar.xz\");\n}\n\n\n/**\n * chsrc get flutter\n */\nvoid\npl_dart_flutter_getsrc (char *option)\n{\n  chsrc_view_env (\"FLUTTER_STORAGE_BASE_URL\", NULL);\n}\n\n\n/**\n * @consult https://mirrors.tuna.tsinghua.edu.cn/flutter\n * @consult https://mirror.sjtu.edu.cn/docs/flutter_infra\n * @consult https://mirror.nju.edu.cn/mirrorz-help/flutter/?mirror=NJU\n */\nvoid\npl_dart_flutter_setsrc (char *option)\n{\n  chsrc_use_this_source (pl_dart_flutter);\n\n  char *w = NULL;\n  char *cmd = NULL;\n  if (xy.on_windows)\n    {\n      cmd = xy_strcat (3, \"setx FLUTTER_STORAGE_BASE_URL \\\"\", source.url, \"\\\"\");\n      chsrc_run (cmd, RunOpt_No_Last_New_Line);\n    }\n  else\n    {\n      char *zshrc  = xy_zshrc;\n      char *bashrc = xy_bashrc;\n\n      chsrc_backup (zshrc);\n      w = xy_strcat (3, \"export FLUTTER_STORAGE_BASE_URL=\\\"\", source.url, \"\\\"\\n\");\n      chsrc_append_to_file (w, zshrc);\n\n      if (xy_file_exist (bashrc))\n        {\n          chsrc_backup (bashrc);\n          chsrc_append_to_file (w, bashrc);\n        }\n    }\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\npl_dart_flutter_resetsrc (char *option)\n{\n  pl_dart_flutter_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/Dart/Pub.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_dart, \"dart/pub\");\n\nvoid\npl_dart_prelude (void)\n{\n  chef_prep_this (pl_dart, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-10\");\n  chef_set_recipe_last_updated (this, \"2025-07-11\");\n  chef_set_sources_last_updated (this, \"2025-04-15\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 2, \"@czyt\", \"@xrgzs\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://pub.dev\",           FeedByPrelude},\n  {&FlutterCN,        \"https://pub.flutter-io.cn\", FeedByPrelude},\n  {&Sjtug_Zhiyuan,    \"https://mirror.sjtu.edu.cn/dart-pub\", FeedByPrelude},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/dart-pub\", FeedByPrelude},\n  {&Nju,              \"https://mirror.nju.edu.cn/dart-pub\", FeedByPrelude}\n  def_sources_end()\n\n  chef_set_rest_smURL_with_postfix (this, \"/packages/flutter_vision/versions/1.1.4.tar.gz\");\n}\n\n\nvoid\npl_dart_getsrc (char *option)\n{\n  chsrc_view_env (\"PUB_HOSTED_URL\", NULL);\n}\n\n/**\n * @consult https://mirrors.tuna.tsinghua.edu.cn/help/dart-pub/\n * @consult https://mirror.sjtu.edu.cn/docs/dart-pub\n * @consult https://mirror.nju.edu.cn/mirrorz-help/dart-pub/?mirror=NJU\n */\nvoid\npl_dart_setsrc (char *option)\n{\n  chsrc_use_this_source (pl_dart);\n\n  char *w = NULL;\n  char *cmd = NULL;\n  if (xy.on_windows)\n    {\n      cmd = xy_strcat (3, \"setx PUB_HOSTED_URL \\\"\", source.url, \"\\\"\");\n      chsrc_run (cmd, RunOpt_No_Last_New_Line);\n    }\n  else\n    {\n      char *zshrc  = xy_zshrc;\n      char *bashrc = xy_bashrc;\n\n      chsrc_backup (zshrc);\n      w = xy_strcat (3, \"export PUB_HOSTED_URL=\\\"\", source.url, \"\\\"\\n\");\n\n      chsrc_append_to_file (w, zshrc);\n\n      if (xy_file_exist (bashrc))\n        {\n          chsrc_backup (bashrc);\n          chsrc_append_to_file (w, bashrc);\n        }\n    }\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\npl_dart_resetsrc (char *option)\n{\n  pl_dart_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/Dart/common.h",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Authors   : MadDogOwner <xiaoran@xrgzs.top>\n * Contributors   :  Nil Null   <nil@null.org>\n *                |\n * Created On     : <2025-04-15>\n * Major Revision :      1\n * Last Modified  : <2025-07-11>\n * ------------------------------------------------------------*/\n\nstatic MirrorSite_t FlutterCN =\n{\n  IS_DedicatedMirrorSite,\n  \"cfug\", \"CFUG\", \"Flutter 社区\", \"https://flutter.cn/\",\n  {NotSkip, NA, NA, \"https://storage.flutter-io.cn/flutter_infra_release/releases/stable/linux/flutter_linux_v1.0.0-stable.tar.xz\", ACCURATE} // 231 MB\n};\n"
  },
  {
    "path": "src/recipe/lang/Go.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\nstatic MirrorSite_t GoProxyCN =\n{\n  IS_DedicatedMirrorSite,\n  \"goproxy.cn\", \"Goproxy.cn\", \"Goproxy.cn (七牛云)\", \"https://goproxy.cn/\",\n  {NotSkip, NA, NA, \"https://goproxy.cn/github.com/aws/aws-sdk-go/@v/v1.45.2.zip\", ACCURATE} // 30 MB\n},\n\nGoProxyIO =\n{\n  IS_DedicatedMirrorSite,\n  \"goproxy.io\", \"GOPROXY.IO\", \"GOPROXY.IO\", \"https://goproxy.io/\",\n  {NotSkip, NA, NA, \"https://goproxy.io/github.com/aws/aws-sdk-go/@v/v1.45.2.zip\", ACCURATE} // 30 MB\n};\n\ndef_target(pl_go, \"go/golang/goproxy\");\n\nvoid\npl_go_prelude ()\n{\n  chef_prep_this (pl_go, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-08-30\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-07-12\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 2, \"@czyt\", \"@techoc\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://proxy.golang.org\", DelegateToUpstream},\n  {&GoProxyCN,        \"https://goproxy.cn\", DelegateToMirror},\n  {&Ali,              \"https://mirrors.aliyun.com/goproxy/\", DelegateToMirror},\n\n  // 暂时停用华为镜像源, 详见 https://github.com/RubyMetric/chsrc/issues/227\n  // {&Huawei,        \"https://mirrors.huaweicloud.com/goproxy/\", DelegateToMirror},\n\n  {&GoProxyIO,        \"https://goproxy.io\", DelegateToMirror}\n  def_sources_end()\n}\n\n\n\nvoid\npl_go_check_cmd ()\n{\n  char *check_cmd = xy_quiet_cmd (\"go version\");\n  bool exist = query_program_exist (check_cmd, \"go\", Noisy_When_Exist|Noisy_When_NonExist);\n\n  if (!exist)\n    {\n      chsrc_error (\"未找到 go 相关命令，请检查是否存在\");\n      exit (Exit_UserCause);\n    }\n}\n\n\nvoid\npl_go_getsrc (char *option)\n{\n  pl_go_check_cmd ();\n  chsrc_run (\"go env GOPROXY\", RunOpt_Default);\n}\n\n\n/**\n * @consult https://goproxy.cn/\n */\nvoid\npl_go_setsrc (char *option)\n{\n  pl_go_check_cmd ();\n\n  chsrc_use_this_source (pl_go);\n\n  char *cmd = \"go env -w GO111MODULE=on\";\n  chsrc_run (cmd, RunOpt_Default);\n\n  cmd = xy_strcat (3, \"go env -w GOPROXY=\", source.url, \",direct\");\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_conclude (&source);\n}\n\n\nvoid\npl_go_resetsrc (char *option)\n{\n  pl_go_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/Haskell.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_haskell, \"haskell/cabal/stack/hackage\");\n\nvoid\npl_haskell_prelude ()\n{\n  chef_prep_this (pl_haskell, s);\n\n  chef_set_recipe_created_on   (this, \"2023-09-10\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-08-22\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@hezonglun\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://hackage.haskell.org\", DelegateToUpstream},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/hackage\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/hackage\",          DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn/hackage\",             DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/hackage\",          DelegateToMirror},\n  {&Iscas,            \"https://mirror.iscas.ac.cn/hackage\",           DelegateToMirror},\n  {&Nyist,            \"https://mirror.nyist.edu.cn/hackage\",          DelegateToMirror}\n  def_sources_end()\n}\n\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/hackage/\n */\nvoid\npl_haskell_setsrc (char *option)\n{\n  chsrc_use_this_source (pl_haskell);\n\n  char *content = xy_str_gsub (RAWSTR_pl_haskell_cabal_config, \"@url@\", source.url);\n\n  char *config = NULL;\n  if (xy.on_windows)\n    {\n      config = xy_normalize_path (\"~/AppData/Roaming/cabal/config\");\n    }\n  else\n    {\n      config = \"~/.cabal/config\";\n    }\n\n  chsrc_note2 (xy_strcat (3, \"请向 \", config, \" 中手动添加:\"));\n  println (content);\n\n  config = xy_normalize_path (\"~/.stack/config.yaml\");\n  content = xy_str_gsub (RAWSTR_pl_haskell_stackage_yaml, \"@url@\", source.url);\n  chsrc_note2 (xy_strcat (3, \"请向 \", config, \" 中手动添加:\"));\n  println (content);\n\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/lang/Java.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_java, \"java/maven/mvn/maven-daemon/mvnd/gradle\");\n\nvoid\npl_java_prelude ()\n{\n  chef_prep_this (pl_java, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-08-31\");\n  chef_set_recipe_last_updated (this, \"2025-08-27\");\n  chef_set_sources_last_updated (this, \"2024-12-18\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 2, \"@BingChunMoLi\", \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Able_And_Implemented);\n  /**\n   * TODO: 当前实现将首先尝试 SystemScope, 若失败则尝试 UserScope\n   * 所以并不是真正意义上的某种 Scope，而是两者的叠加，后续考虑强制执行用户所选择的 Scope 以达到用户期待\n   */\n  chef_set_default_scope (this, ImplementationDefinedScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  // 阿里巴巴开源镜像站需要修改为此才能测速\n  // https://github.com/RubyMetric/chsrc/issues/238#issuecomment-3162367686\n  chef_set_user_agent (\"Maven/3.9.11\");\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://repo1.maven.org/maven2/\",                                 FeedByPrelude},\n  {&Ali,              \"https://maven.aliyun.com/repository/public/\",                     FeedByPrelude},\n  {&Huawei,           \"https://mirrors.huaweicloud.com/repository/maven/\",               FeedByPrelude},\n  {&HuaweiCDN,        \"https://repo.huaweicloud.com/repository/maven/\",                  FeedByPrelude},\n  {&Tencent,          \"https://mirrors.cloud.tencent.com/nexus/repository/maven-public/\",FeedByPrelude},\n  // 网易的24小时更新一次\n  {&Netease,          \"http://mirrors.163.com/maven/repository/maven-public/\",           FeedByPrelude}\n  def_sources_end()\n\n  // 220MB\n  chef_set_rest_smURL_with_postfix (this, \"com/tencentcloudapi/tencentcloud-sdk-java/3.1.1033/tencentcloud-sdk-java-3.1.1033-javadoc.jar\");\n}\n\n\nvoid\npl_java_check_cmd (bool *maven_exist, bool *gradle_exist, bool *maven_daemon_exist)\n{\n  *maven_exist  = chsrc_check_program (\"mvn\");\n  *gradle_exist = chsrc_check_program (\"gradle\");\n  *maven_daemon_exist = chsrc_check_program (\"mvnd\");\n\n  if (! *maven_exist && ! *gradle_exist && ! *maven_daemon_exist)\n    {\n      chsrc_error (\"maven(maven-daemon) 与 gradle 命令均未找到，请检查是否存在其一\");\n      exit (Exit_UserCause);\n    }\n}\n\n\nbool\npl_java_is_maven_home_line (const char *line)\n{\n  if (xy_str_start_with (line, \"Maven home:\"))\n    return true;\n  else\n    return false;\n}\n\n\n/**\n * @consult https://github.com/RubyMetric/chsrc/pull/268#issuecomment-3209071819\n */\nchar *\npl_java_find_maven_config ()\n{\n  char *output;\n  int status = xy_run_get_stdout (\"mvn -v\", &output);\n  if (0==status)\n    {\n      char *maven_home_line = xy_run_iter_lines (\"mvn -v\", 0, pl_java_is_maven_home_line);\n      char *maven_home = xy_str_delete_prefix (maven_home_line, \"Maven home: \");\n      char *maven_config = xy_normalize_path (xy_2strcat (maven_home, \"/conf/settings.xml\"));\n      return maven_config;\n    }\n\n  chsrc_alert2 (\"未找到 maven home, 将使用用户配置文件\");\n  return \"~/.m2/settings.xml\";\n}\n\nchar *\npl_java_find_maven_daemon_config ()\n{\n  char *output;\n  int status = xy_run_get_stdout (\"mvnd -v\", &output);\n  if (0==status)\n    {\n      char *maven_home_line = xy_run_iter_lines (\"mvnd -v\", 0, pl_java_is_maven_home_line);\n      char *maven_home = xy_str_delete_prefix (maven_home_line, \"Maven home: \");\n      char *maven_config = xy_normalize_path (xy_2strcat (maven_home, \"/conf/settings.xml\"));\n      return maven_config;\n    }\n\n  chsrc_alert2 (\"未找到 maven home, 将使用用户配置文件\");\n  return \"~/.m2/settings.xml\";\n}\n\n\nvoid\npl_java_getsrc (char *option)\n{\n  bool maven_exist, gradle_exist, maven_daemon_exist;\n  pl_java_check_cmd (&maven_exist, &gradle_exist, &maven_daemon_exist);\n  if (maven_exist)\n    {\n      char *maven_config = pl_java_find_maven_config ();\n      chsrc_note2 (xy_2strcat (\"请查看 \", maven_config));\n    }\n  if (maven_daemon_exist)\n    {\n      char *maven_config = pl_java_find_maven_daemon_config ();\n      chsrc_note2 (xy_2strcat (\"请查看 \", maven_config));\n    }\n}\n\n\n\n/**\n * @consult https://developer.aliyun.com/mirror/maven\n */\nvoid\npl_java_setsrc (char *option)\n{\n  bool maven_exist, gradle_exist, maven_daemon_exist;\n  pl_java_check_cmd (&maven_exist, &gradle_exist, &maven_daemon_exist);\n\n  chsrc_use_this_source(pl_java);\n  if (maven_exist)\n    {\n      char *file = xy_str_gsub (RAWSTR_pl_java_maven_config, \"@1@\", source.mirror->code);\n            file = xy_str_gsub (file, \"@name@\", source.mirror->name);\n            file = xy_str_gsub (file, \"@url@\", source.url);\n      char *maven_config = pl_java_find_maven_config ();\n      chsrc_note2 (xy_strcat (3, \"请在 maven 配置文件 \", maven_config, \" 中添加:\"));\n      println (file);\n    }\n\n  if (maven_daemon_exist)\n    {\n      char *file = xy_str_gsub (RAWSTR_pl_java_maven_config, \"@1@\", source.mirror->code);\n            file = xy_str_gsub (file, \"@name@\", source.mirror->name);\n            file = xy_str_gsub (file, \"@url@\", source.url);\n      char *maven_daemon_config = pl_java_find_maven_daemon_config ();\n      chsrc_note2 (xy_strcat (3, \"请在 maven daemon 配置文件 \", maven_daemon_config, \" 中添加:\"));\n      println (file);\n    }\n\n  if (gradle_exist)\n    {\n      if (maven_exist) br();\n      char* file = xy_str_gsub (RAWSTR_pl_java_build_gradle, \"@url@\", source.url);\n      chsrc_note2 (\"请在 build.gradle 中添加:\");\n      println (file);\n    }\n\n  chsrc_conclude (&source);\n}\n\n\nvoid\npl_java_resetsrc (char *option)\n{\n  pl_java_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/JavaScript/Bun.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_js_bun, \"bun\");\n\nvoid\npl_js_bun_prelude (void)\n{\n  chef_prep_this (pl_js_bun, gsr);\n\n  chef_set_recipe_created_on   (this, \"2024-09-29\");\n  chef_set_recipe_last_updated (this, \"2025-07-22\");\n  chef_set_sources_last_updated (this, \"2025-07-22\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@lontten\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  chef_use_other_target_sources (this, &pl_js_group_target);\n}\n\n/**\n * chsrc get bun\n */\nvoid\npl_js_bun_getsrc (char *option)\n{\n  chsrc_view_file (\"~/.bunfig.toml\");\n}\n\n\n/**\n * @consult https://bun.sh/docs/runtime/bunfig#global-vs-local\n * @consult https://github.com/RubyMetric/chsrc/issues/83\n * @consult https://github.com/RubyMetric/chsrc/pull/90\n *\n * chsrc set bun\n */\nvoid\npl_js_bun_setsrc (char *option)\n{\n  // 用的是 npm Registry 的源\n  Source_t source = chsrc_yield_source_and_confirm (&pl_js_group_target, option);\n\n  char *content = RAWSTR_pl_js_bun_config;\n\n  content = xy_str_gsub (content, \"@url@\", source.url);\n\n  if (chsrc_in_project_scope_mode())\n    {\n      chsrc_note2 (\"请手动写入以下内容到本项目根目录的 bunfig.toml 文件中\");\n    }\n  else\n    {\n      chsrc_note2 (xy_strcat (3, \"请手动写入以下内容到 \", xy_normalize_path (\"~/.bunfig.toml\"), \" 文件中\"));\n    }\n\n  println (content);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\n/**\n * chsrc reset bun\n */\nvoid\npl_js_bun_resetsrc (char *option)\n{\n  pl_js_bun_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/JavaScript/JavaScript.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Authors   : Aoran Zeng <ccmywish@qq.com>\n * Contributors   :  Mr. Will  <mr.will.com@outlook.com>\n *                |\n * Created On     : <2023-08-30>\n * Major Revision :      2\n * Last Modified  : <2025-07-11>\n * ------------------------------------------------------------*/\n\nvoid\npl_js_check_cmd (bool *npm_exist, bool *yarn_exist, bool *pnpm_exist)\n{\n  *npm_exist  = chsrc_check_program (\"npm\");\n  *yarn_exist = chsrc_check_program (\"yarn\");\n  *pnpm_exist = chsrc_check_program (\"pnpm\");\n\n  if (!*npm_exist && !*yarn_exist && !*pnpm_exist)\n    {\n      char *msg = ENGLISH ? \"No npm, yarn or pnpm command found, check if at least one is present\"\n                          : \"未找到 npm 或 yarn 或 pnpm 命令，请检查是否存在其一\";\n      chsrc_error (msg);\n      exit (Exit_UserCause);\n    }\n}\n\n\nvoid\npl_js_group_getsrc (char *option)\n{\n  bool npm_exist, yarn_exist, pnpm_exist;\n  pl_js_check_cmd (&npm_exist, &yarn_exist, &pnpm_exist);\n\n  hr();\n\n  if (npm_exist)\n    {\n      pl_js_npm_getsrc (option);\n      br();\n    }\n\n  if (yarn_exist)\n    {\n      pl_js_yarn_getsrc (option);\n      br();\n    }\n\n  if (pnpm_exist)\n    {\n      pl_js_pnpm_getsrc (option);\n      br();\n    }\n}\n\n\nvoid\npl_js_group_setsrc (char *option)\n{\n  {\n    char *msg = ENGLISH ? \"Three package managers will be replaced for you at the same time: \"\n                          \"npm, pnpm, yarn. If you need to change the source independently, \"\n                          \"please run independently `chsrc set <pkg-manager>`\"\n                        : \"将同时更换3个包管理器 npm, pnpm, Yarn 的源，若需要独立换源，请独立运行 chsrc set <pkg-manager>\";\n    chsrc_alert2 (msg);\n  }\n\n  bool npm_exist, yarn_exist, pnpm_exist;\n  pl_js_check_cmd (&npm_exist, &yarn_exist, &pnpm_exist);\n\n  chsrc_set_target_group_mode ();\n\n  chsrc_use_this_source (pl_js_group);\n\n  if (npm_exist)\n    {\n      pl_js_npm_setsrc (option);\n      br();\n    }\n\n  if (yarn_exist)\n    {\n      pl_js_yarn_setsrc (option);\n      br();\n    }\n\n  if (pnpm_exist)\n    {\n      pl_js_pnpm_setsrc (option);\n    }\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\npl_js_group_resetsrc (char *option)\n{\n  pl_js_group_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/JavaScript/Yarn.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_js_yarn, \"yarn\");\n\nvoid\npl_js_yarn_prelude (void)\n{\n  chef_prep_this (pl_js_yarn, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-09\");\n  chef_set_recipe_last_updated (this, \"2025-07-11\");\n  chef_set_sources_last_updated (this, \"2025-07-11\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@MrWillCom\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  chef_use_other_target_sources (this, &pl_js_group_target);\n}\n\nstatic double\npl_js_yarn_get_yarn_version ()\n{\n  char *ver = xy_run (\"yarn --version\", 0);\n  double version = atof (ver);\n  return version;\n}\n\n\nvoid\npl_js_yarn_getsrc (char *option)\n{\n  // 最后一个版本应该是 v1.22.22\n  if (pl_js_yarn_get_yarn_version () >= 2)\n    // https://github.com/RubyMetric/chsrc/issues/53\n    // 从 Yarn V2 开始，使用新的配置名\n    chsrc_run (\"yarn config get npmRegistryServer\", RunOpt_No_Last_New_Line);\n  else\n    chsrc_run (\"yarn config get registry\", RunOpt_No_Last_New_Line);\n}\n\n\n/**\n * @consult https://github.com/RubyMetric/chsrc/issues/53\n * @consult https://yarnpkg.com/cli/config/set\n */\nvoid\npl_js_yarn_setsrc (char *option)\n{\n  Source_t source = chsrc_yield_source (&pl_js_group_target, option);\n  if (chsrc_in_standalone_mode())\n    chsrc_confirm_source(&source);\n\n  char *cmd = NULL;\n\n  // 从 Yarn V2 开始，使用新的配置名\n  if (pl_js_yarn_get_yarn_version () >= 2)\n    {\n      if (chsrc_in_project_scope_mode()) // Yarn 默认情况下就是基于本项目换源\n        cmd = xy_2strcat (\"yarn config set npmRegistryServer \", source.url);\n      else\n        cmd = xy_2strcat (\"yarn config set npmRegistryServer --home \", source.url);\n\n      chsrc_run (cmd, RunOpt_No_Last_New_Line);\n    }\n  else\n    {\n      if (chsrc_in_project_scope_mode())\n        {\n          char *msg = ENGLISH ? \"Yarn v1 doesn't support `-scope=project`. SKIP changing source!\"\n                              : \"Yarn v1 不支持项目级换源，跳过换源\";\n          chsrc_error (msg);\n          // 不能直接退出，因为 Leader target 不能就此结束\n          return;\n        }\n      // 不再阻止换源命令输出到终端，即不再调用 xy_quiet_cmd()\n      cmd = xy_2strcat (\"yarn config set registry \", source.url);\n      chsrc_run (cmd, RunOpt_No_Last_New_Line);\n    }\n\n  if (chsrc_in_standalone_mode())\n    {\n      chsrc_determine_chgtype (ChgType_Auto);\n      chsrc_conclude (&source);\n    }\n}\n\n\nvoid\npl_js_yarn_resetsrc (char *option)\n{\n  pl_js_yarn_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/JavaScript/common.h",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\nstatic MirrorSite_t NpmMirror =\n{\n  IS_DedicatedMirrorSite,\n  \"npmmirror\", \"npmmirror\", \"npmmirror (阿里云赞助)\", \"https://npmmirror.com/\",\n  {SKIP, NULL, NULL, NULL, ACCURATE}\n};\n\ndef_target(pl_js_group, \"js/javascript/node/nodejs\");\n\nvoid\npl_js_group_prelude (void)\n{\n  chef_prep_this (pl_js_group, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-09\");\n  chef_set_recipe_last_updated (this, \"2025-07-11\");\n  chef_set_sources_last_updated (this, \"2025-07-11\");\n\n  chef_set_chef (this, \"@happy-game\");\n  // 组换源的 leader target 应把所有 follower target 的贡献者都记录过来\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 2, \"@lontten\", \"@MrWillCom\");\n\n  /* ProjectScope 支持 npm, yarn v2, pnpm, 不支持 yarn v1 */\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://registry.npmjs.org/\",    FeedByPrelude}, /* @note 根据 pnpm 官网，有最后的斜线 */\n  {&NpmMirror,        \"https://registry.npmmirror.com\", FeedByPrelude},\n  {&Huawei,           \"https://mirrors.huaweicloud.com/repository/npm/\", FeedByPrelude},\n  {&Tencent,          \"https://mirrors.cloud.tencent.com/npm/\", FeedByPrelude}\n  def_sources_end()\n\n  // 29MB 大小\n  chef_set_rest_smURL_with_postfix (this, \"/@tensorflow/tfjs/-/tfjs-4.22.0.tgz\");\n}\n\n\n\ndef_target(pl_js_nodejs_binary, \"__internal_target_nodejs_binary__\");\n\nvoid\npl_js_nodejs_binary_prelude (void)\n{\n  chef_prep_this (pl_js_nodejs_binary, NOOP);\n\n  chef_set_recipe_created_on   (this, \"2023-09-09\");\n  chef_set_recipe_last_updated (this, \"2025-08-22\");\n  chef_set_sources_last_updated (this, \"2025-07-11\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider,  \"https://nodejs.org/dist/\", FeedByPrelude},\n  {&NpmMirror, \"https://npmmirror.com/mirrors\", FeedByPrelude},\n  {&Tuna,      \"https://mirrors.tuna.tsinghua.edu.cn/nodejs-release/\",FeedByPrelude},\n  {&Bfsu,      \"https://mirrors.bfsu.edu.cn/nodejs-release/\",FeedByPrelude},\n  {&Ustc,      \"https://mirrors.ustc.edu.cn/node/\",FeedByPrelude},\n  {&Huawei,    \"https://mirrors.huaweicloud.com/nodejs/\",FeedByPrelude},\n  {&Tencent,   \"https://mirrors.cloud.tencent.com/nodejs-release/\", FeedByPrelude}\n  def_sources_end()\n\n  chef_set_rest_smURL_with_postfix (this, \"/v23.4.0/node-v23.4.0-linux-x64.tar.xz\");\n}\n"
  },
  {
    "path": "src/recipe/lang/JavaScript/npm.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_js_npm, \"npm\");\n\nvoid\npl_js_npm_prelude (void)\n{\n  chef_prep_this (pl_js_npm, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-08-30\");\n  chef_set_recipe_last_updated (this, \"2025-07-11\");\n  chef_set_sources_last_updated (this, \"2025-07-11\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@MrWillCom\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  chef_use_other_target_sources (this, &pl_js_group_target);\n}\n\n\nvoid\npl_js_npm_getsrc (char *option)\n{\n  chsrc_run (\"npm config get registry\", RunOpt_No_Last_New_Line);\n}\n\n\n/**\n * @consult https://npmmirror.com/\n */\nvoid\npl_js_npm_setsrc (char *option)\n{\n  Source_t source = chsrc_yield_source (&pl_js_group_target, option);\n  if (chsrc_in_standalone_mode())\n    chsrc_confirm_source(&source);\n\n  char *cmd = NULL;\n\n  if (chsrc_in_project_scope_mode())\n    cmd = xy_2strcat (\"npm config --location project set registry \", source.url);\n  else\n    cmd = xy_2strcat (\"npm config set registry \", source.url);\n\n  chsrc_run (cmd, RunOpt_No_Last_New_Line);\n\n  if (chsrc_in_standalone_mode())\n    {\n      chsrc_determine_chgtype (ChgType_Auto);\n      chsrc_conclude (&source);\n    }\n}\n\n\nvoid\npl_js_npm_resetsrc (char *option)\n{\n  pl_js_npm_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/JavaScript/nvm.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_js_nvm, \"nvm\");\n\nvoid\npl_js_nvm_prelude (void)\n{\n  chef_prep_this (pl_js_nvm, gsr);\n\n  chef_set_recipe_created_on   (this, \"2024-09-23\");\n  chef_set_recipe_last_updated (this, \"2025-06-19\");\n  chef_set_sources_last_updated (this, \"2025-06-19\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  chef_set_note (this, \"nvm 不支持 Fish shell\", \"nvm does not support Fish\");\n\n  chef_use_other_target_sources (this, &pl_js_nodejs_binary_target);\n}\n\n\nvoid\npl_js_nvm_getsrc (char *option)\n{\n  chsrc_view_env (\"NVM_NODEJS_ORG_MIRROR\", NULL);\n}\n\n\n/**\n * @consult https://github.com/nvm-sh/nvm?tab=readme-ov-file#use-a-mirror-of-node-binaries\n * @consult https://mirrors.tuna.tsinghua.edu.cn/help/nodejs-release/\n * @issue   https://github.com/RubyMetric/chsrc/issues/81\n *\n * @note nvm 不支持 Fish\n */\nvoid\npl_js_nvm_setsrc (char *option)\n{\n  Source_t source = chsrc_yield_source_and_confirm (&pl_js_nodejs_binary_target, option);\n\n  char *w = xy_strcat (3, \"export NVM_NODEJS_ORG_MIRROR=\", source.url, \"\\n\");\n\n  char *zshrc  = xy_zshrc;\n  char *bashrc = xy_bashrc;\n\n  chsrc_append_to_file (w, bashrc);\n\n  if (xy_file_exist (zshrc))\n    chsrc_append_to_file (w, zshrc);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\npl_js_nvm_resetsrc (char *option)\n{\n  // pl_js_nvm_setsrc (ChgType_Reset);\n  chsrc_error (\"暂不支持对 nvm 重置\");\n  exit (Exit_Unsupported);\n}\n"
  },
  {
    "path": "src/recipe/lang/JavaScript/pnpm.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_js_pnpm, \"pnpm\");\n\nvoid\npl_js_pnpm_prelude (void)\n{\n  chef_prep_this (pl_js_pnpm, gsr);\n\n  chef_set_recipe_created_on   (this, \"2024-04-18\");\n  chef_set_recipe_last_updated (this, \"2025-07-11\");\n  chef_set_sources_last_updated (this, \"2025-07-11\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  chef_use_other_target_sources (this, &pl_js_group_target);\n}\n\n\nvoid\npl_js_pnpm_getsrc (char *option)\n{\n  chsrc_run (\"pnpm config get registry\", RunOpt_No_Last_New_Line);\n}\n\n\n/**\n * @consult https://pnpm.io/feature-comparison\n * @consult https://pnpm.io/cli/config\n */\nvoid\npl_js_pnpm_setsrc (char *option)\n{\n  Source_t source = chsrc_yield_source (&pl_js_group_target, option);\n  if (chsrc_in_standalone_mode())\n    chsrc_confirm_source(&source);\n\n  char *cmd = NULL;\n\n  if (chsrc_in_project_scope_mode())\n    cmd = xy_2strcat (\"pnpm config --location project set registry \", source.url);\n  else\n    cmd = xy_2strcat (\"pnpm config -g set registry \", source.url);\n\n  chsrc_run (cmd, RunOpt_No_Last_New_Line);\n\n  if (chsrc_in_standalone_mode())\n    {\n      chsrc_determine_chgtype (ChgType_Auto);\n      chsrc_conclude (&source);\n    }\n}\n\n\nvoid\npl_js_pnpm_resetsrc (char *option)\n{\n  pl_js_pnpm_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/Julia.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_julia, \"julia\");\n\nvoid\npl_julia_prelude ()\n{\n  chef_prep_this (pl_julia, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-08-31\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-08-22\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@hezonglun\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://pkg.julialang.org\", DelegateToUpstream},\n  {&Pku,              \"https://mirrors.pku.edu.cn/julia\", DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn/julia\",   DelegateToMirror},\n  {&Iscas,            \"https://mirror.iscas.ac.cn/julia\",  DelegateToMirror}\n  def_sources_end()\n}\n\n#define PL_Julia_Config \"~/.julia/config/startup.jl\"\n\n/**\n * Julia的换源可以通过两种方式\n * 1. 写入 startup.jl\n * 2. 使用环境变量\n *\n * 我们采用第一种\n */\nvoid\npl_julia_getsrc (char *option)\n{\n  chsrc_view_file (PL_Julia_Config);\n}\n\n/**\n * @consult\n *  1. https://help.mirrors.cernet.edu.cn/julia/\n *  2. https://docs.julialang.org/en/v1/manual/command-line-interface/#Startup-file\n */\nvoid\npl_julia_setsrc (char *option)\n{\n  chsrc_use_this_source (pl_julia);\n\n  char *w = xy_strcat (3, \"ENV[\\\"JULIA_PKG_SERVER\\\"] = \\\"\", source.url, \"\\\"\");\n\n  chsrc_append_to_file (w, PL_Julia_Config);\n\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/lang/Lua.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\nstatic MirrorSite_t Api7 =\n{\n  IS_DedicatedMirrorSite,\n  \"api7\", \"api7.ai\", \"深圳支流科技有限公司\", \"https://www.apiseven.com/\",\n  {SKIP, ToFill, ToFill, NULL, ROUGH}\n};\n\ndef_target(pl_lua, \"lua/luarocks\");\n\nvoid\npl_lua_prelude ()\n{\n  chef_prep_this (pl_lua, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-27\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-08-22\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@hezonglun\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://luarocks.org\", DelegateToUpstream},\n  {&Api7,             \"https://luarocks.cn\", DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\npl_lua_getsrc (char *option)\n{\n  chsrc_view_file (\"~/.luarocks/config.lua\");\n  chsrc_view_file (\"~/.luarocks/upload_config.lua\");\n}\n\n/**\n * @consult https://luarocks.cn/\n */\nvoid\npl_lua_setsrc (char *option)\n{\n  chsrc_use_this_source (pl_lua);\n\n  char *config = xy_strcat (3, \"rocks_servers = {\\n\"\n                                \"  \\\"\", source.url, \"\\\"\\n\"\n                                \"}\");\n\n  chsrc_note2 (\"请手动修改 ~/.luarocks/config.lua 文件 (用于下载):\");\n  println (config);\n\n  char *upload_config = xy_strcat (3, \"key = \\\"<Your API Key>\\\"\\n\"\n                                      \"server = \\\"\", source.url, \"\\\"\");\n\n  chsrc_note2 (\"请手动修改 ~/.luarocks/upload_config.lua 文件 (用于上传):\");\n  println (upload_config);\n\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/lang/NuGet.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_nuget, \"nuget/net/.net/dotnet\");\n\nvoid\npl_nuget_prelude ()\n{\n  chef_prep_this (pl_nuget, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-10\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2024-04-18\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://www.nuget.org/api/v3/\", DelegateToUpstream},\n  {&Huawei,           \"https://mirrors.huaweicloud.com/repository/nuget/v3\", DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\npl_nuget_getsrc (char *option)\n{\n  chsrc_error (\"暂时无法查看NuGet源，若有需求，请提交issue\");\n}\n\n\n/**\n * 暂时未实现该换源功能，可参照 https://mirrors.huaweicloud.com/mirrorDetail/5ebf85de07b41baf6d0882ab?mirrorName=nuget&catalog=language\n */\nvoid\npl_nuget_setsrc (char *option)\n{\n  chsrc_error (\"暂时无法为NuGet换源，若有需求，请提交issue\");\n}\n"
  },
  {
    "path": "src/recipe/lang/OCaml.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_ocaml, \"ocaml/opam\");\n\nvoid\npl_ocaml_prelude ()\n{\n  chef_prep_this (pl_ocaml, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-15\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-07-14\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@hezonglun\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider,  \"https://opam.ocaml.org/\", DelegateToUpstream},\n  {&Sjtug_Zhiyuan,     \"https://mirrors.sjtug.sjtu.edu.cn/git/opam-repository.git\", DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\npl_ocaml_check_cmd ()\n{\n  chsrc_ensure_program (\"opam\");\n}\n\n\nvoid\npl_ocaml_getsrc (char *option)\n{\n  pl_ocaml_check_cmd ();\n  chsrc_run (\"opam repo get-url default\", RunOpt_Default);\n}\n\n\n/**\n * @consult https://mirrors.sjtug.sjtu.edu.cn/docs/git/opam-repository.git\n */\nvoid\npl_ocaml_setsrc (char *option)\n{\n  pl_ocaml_check_cmd ();\n\n  chsrc_use_this_source (pl_ocaml);\n\n  char *cmd = xy_strcat (3, \"opam repo set-url default \",\n                              source.url,\n                             \" --all --set-default\");\n\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_alert2 (\"如果是首次使用 opam ，请使用以下命令进行初始化\");\n  println (xy_2strcat (\"opam init default \", source.url));\n\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/lang/PHP.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_php, \"php/composer\");\n\nvoid\npl_php_prelude ()\n{\n  chef_prep_this (pl_php, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-08-30\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-08-24\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@hezonglun\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://packagist.org/\", DelegateToUpstream},\n  {&Ali,              \"https://mirrors.aliyun.com/composer/\",     DelegateToMirror},\n  {&Tencent,          \"https://mirrors.tencent.com/composer/\",    DelegateToMirror},\n  // {&Tencent_Intra, \"https://mirrors.tencentyun.com/composer/\", DelegateToMirror},\n  {&Huawei,           \"https://mirrors.huaweicloud.com/repository/php/\", DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\npl_php_check_cmd ()\n{\n  chsrc_ensure_program (\"composer\");\n}\n\n/**\n * 已在Windows上测试通过，待其他平台PHP用户确认\n */\nvoid\npl_php_getsrc (char *option)\n{\n  pl_php_check_cmd ();\n  chsrc_run (\"composer config -g repositories\", RunOpt_Default);\n}\n\n/**\n * @consult https://developer.aliyun.com/composer\n */\nvoid\npl_php_setsrc (char *option)\n{\n  pl_php_check_cmd ();\n\n  chsrc_use_this_source (pl_php);\n\n  char *where = \" -g \";\n  if (chsrc_in_project_scope_mode())\n    {\n      where = \" \";\n    }\n\n  char *cmd = xy_strcat (4, \"composer config\", where, \"repo.packagist composer \", source.url);\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/lang/Perl.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_perl, \"perl/cpan\");\n\nvoid\npl_perl_prelude ()\n{\n  chef_prep_this (pl_perl, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-31\");\n  chef_set_recipe_last_updated (this, \"2025-10-07\");\n  chef_set_sources_last_updated (this, \"2025-10-07\");\n\n  chef_set_chef     (this, NULL);\n  chef_set_cooks    (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 2, \"@hezonglun\", \"@Mikachu2333\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english    (this);\n  chef_allow_user_define (this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://www.cpan.org/\",                      FeedByPrelude},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/CPAN/\",        FeedByPrelude},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/CPAN/\", FeedByPrelude},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/CPAN/\",          FeedByPrelude},\n  {&Cqu,              \"https://mirrors.cqu.edu.cn/CPAN/\",           FeedByPrelude},\n  {&Bjtu,             \"https://mirror.bjtu.edu.cn/cpan/\",           FeedByPrelude},\n  {&Nju,              \"https://mirrors.nju.edu.cn/CPAN/\",           FeedByPrelude},\n  {&Nyist,            \"https://mirror.nyist.edu.cn/CPAN/\",          FeedByPrelude},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/CPAN/\",          FeedByPrelude},\n  {&Sjtug_Siyuan,     \"https://mirror.sjtu.edu.cn/cpan/\",           FeedByPrelude},\n  {&Iscas,            \"https://mirror.iscas.ac.cn/CPAN/\",           FeedByPrelude},\n  {&Zju,              \"https://mirrors.zju.edu.cn/CPAN/\",           FeedByPrelude},\n  {&Lzuoss,           \"https://mirrors.lzu.edu.cn/CPAN/\",           FeedByPrelude},\n  {&Hust,             \"https://mirrors.hust.edu.cn/CPAN/\",          FeedByPrelude},\n  {&Ali,              \"https://mirrors.aliyun.com/CPAN/\",           FeedByPrelude}\n  def_sources_end()\n\n  chef_set_rest_smURL_with_postfix (this, \"authors/id/D/DB/DBAURAIN/Bio-MUST-Apps-FortyTwo-0.213470.tar.gz\");\n}\n\n\nvoid\npl_perl_check_cmd ()\n{\n  chsrc_ensure_program (\"perl\");\n}\n\nvoid\npl_perl_getsrc (char *option)\n{\n  pl_perl_check_cmd ();\n  // @ccmywish: 注意，prettyprint 仅仅是一个内部实现，可能不稳定，如果需要更稳定的，\n  //            可以使用 CPAN::Shell->o('conf', 'urllist');\n  //            另外，上述两种方法无论哪种，都要首先load()\n  char *cmd = \"perl -MCPAN -e \\\"CPAN::HandleConfig->load(); CPAN::HandleConfig->prettyprint('urllist')\\\" \";\n  chsrc_run (cmd, RunOpt_Default);\n}\n\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/CPAN/\n */\nvoid\npl_perl_setsrc (char *option)\n{\n  chsrc_use_this_source (pl_perl);\n\n  char *cmd = xy_strcat (3,\n  \"perl -MCPAN -e \\\"CPAN::HandleConfig->load(); CPAN::HandleConfig->edit('urllist', 'unshift', '\", source.url, \"'); CPAN::HandleConfig->commit()\\\"\");\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_alert2 (\"请使用 perl -v 以及 cpan -v，若 Perl >= v5.36 或 CPAN >= 2.29，请额外手动调用下面的命令\");\n  p (\"perl -MCPAN -e \\\"CPAN::HandleConfig->load(); CPAN::HandleConfig->edit('pushy_https', 0);; CPAN::HandleConfig->commit()\\\"\");\n\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/lang/Python/PDM.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_python_pdm, \"pdm\");\n\nvoid\npl_python_pdm_prelude (void)\n{\n  chef_prep_this (pl_python_pdm, gsr);\n\n  chef_set_recipe_created_on   (this, \"2024-06-05\");\n  chef_set_recipe_last_updated (this, \"2025-07-11\");\n  chef_set_sources_last_updated (this, \"2025-07-11\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  chef_use_other_target_sources (this, &pl_python_group_target);\n}\n\n\nvoid\npl_python_pdm_getsrc (char *option)\n{\n  // @HELP 不加 --global 时，会检测到本项目的配置吗？\n  // 如果不行的话，就要分别改成 --global 和 --local\n  char *cmd = \"pdm config pypi.url\";\n  chsrc_run (cmd, RunOpt_Default);\n}\n\n\n/**\n * @consult https://github.com/RubyMetric/chsrc/issues/19\n */\nvoid\npl_python_pdm_setsrc (char *option)\n{\n  Source_t source = chsrc_yield_source (&pl_python_group_target, option);\n  if (chsrc_in_standalone_mode())\n    chsrc_confirm_source(&source);\n\n  char *cmd = NULL;\n\n  if (chsrc_in_project_scope_mode())\n    cmd = xy_2strcat (\"pdm config --local pypi.url \", source.url);\n  else\n    cmd = xy_2strcat (\"pdm config --global pypi.url \", source.url);\n\n  chsrc_run (cmd, RunOpt_No_Last_New_Line);\n\n  if (chsrc_in_standalone_mode())\n    {\n      chsrc_determine_chgtype (ChgType_Auto);\n      chsrc_conclude (&source);\n    }\n}\n\nvoid\npl_python_pdm_resetsrc (char *option)\n{\n  pl_python_pdm_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/Python/Poetry.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_python_poetry, \"poetry\");\n\nvoid\npl_python_poetry_prelude (void)\n{\n  chef_prep_this (pl_python_poetry, gsr);\n\n  chef_set_recipe_created_on   (this, \"2024-08-08\");\n  chef_set_recipe_last_updated (this, \"2025-07-11\");\n  chef_set_sources_last_updated (this, \"2025-07-11\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  /* Poetry 仅支持项目级换源 */\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Unable);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, ProjectScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  chef_use_other_target_sources (this, &pl_python_group_target);\n}\n\nvoid\npl_python_poetry_getsrc (char *option)\n{\n  chsrc_note2 (\"poetry换源情况: 请查看本项目 pyproject.toml 中 [[tool.poetry.source]]\");\n}\n\n\n/**\n * @consult https://python-poetry.org/docs/repositories/#project-configuration\n */\nvoid\npl_python_poetry_setsrc (char *option)\n{\n  Source_t source = chsrc_yield_source (&pl_python_group_target, option);\n  if (chsrc_in_standalone_mode())\n    chsrc_confirm_source(&source);\n\n  char *cmd = xy_2strcat (\"poetry source add my_mirror \", source.url);\n  chsrc_run (cmd, RunOpt_No_Last_New_Line);\n\n  if (chsrc_in_standalone_mode())\n    {\n      chsrc_determine_chgtype (ChgType_Auto);\n      chsrc_conclude (&source);\n    }\n}\n\n\nvoid\npl_python_poetry_resetsrc (char *option)\n{\n  pl_python_poetry_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/Python/Python.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Authors  : @ccmywish\n * Contributors  : @happy-game\n *               |\n * Created On    : <2023-09-03>\n * Last Modified : <2025-12-31>\n * ------------------------------------------------------------*/\n\nvoid\npl_python_group_getsrc (char *option)\n{\n  bool pdm_exist    = false,\n       poetry_exist = false,\n       uv_exist     = false;\n\n  pl_python_check_unofficial_pkger (&poetry_exist, &pdm_exist, &uv_exist);\n\n  // 交给后面检查命令的存在性\n  pl_python_pip_getsrc (option);\n  br();\n\n  if (poetry_exist)\n    {\n      pl_python_poetry_getsrc (option);\n      br();\n    }\n\n  if (pdm_exist)\n    {\n      pl_python_pdm_getsrc (option);\n    }\n\n  if (uv_exist)\n    {\n      pl_python_uv_getsrc (option);\n    }\n}\n\n\nvoid\npl_python_group_setsrc (char *option)\n{\n  {\n    char *msg = ENGLISH ? \"Three package managers will be replaced for you at the same time: \"\n                          \"pip, Poetry, PDM. If you need to change the source independently, \"\n                          \"please run independently `chsrc set <pkg-manager>`\"\n                        : \"将同时更换4个包管理器 pip, Poetry, PDM, uv 的源，若需要独立换源，请独立运行 chsrc set <pkg-manager>\";\n    chsrc_alert2 (msg);\n  }\n\n  bool pdm_exist    = false,\n       poetry_exist = false,\n       uv_exist     = false;\n\n  pl_python_check_unofficial_pkger (&poetry_exist, &pdm_exist, &uv_exist);\n\n  chsrc_set_target_group_mode ();\n\n  chsrc_use_this_source (pl_python_group);\n\n\n  // 交给后面检查命令的存在性\n  pl_python_pip_setsrc (option);\n  br();\n\n  if (poetry_exist)\n    {\n      pl_python_poetry_setsrc (option);\n      br();\n    }\n\n  if (pdm_exist)\n    {\n      pl_python_pdm_setsrc (option);\n    }\n\n  if (uv_exist)\n    {\n      pl_python_uv_setsrc (option);\n    }\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\npl_python_group_resetsrc (char *option)\n{\n  pl_python_group_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/Python/Rye.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * 由于Rye已经有后继uv了，所以我们不把该管理器纳入Python group中\n * ------------------------------------------------------------*/\n\ndef_target(pl_python_rye, \"rye\");\n\nvoid\npl_python_rye_prelude (void)\n{\n  chef_prep_this (pl_python_rye, gsr);\n\n  chef_set_recipe_created_on   (this, \"2024-12-06\");\n  chef_set_recipe_last_updated (this, \"2025-08-09\");\n  chef_set_sources_last_updated (this, \"2025-08-09\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  chef_use_other_target_sources (this, &pl_python_group_target);\n}\n\nchar *\npl_python_find_rye_config ()\n{\n  char *buf = xy_run (\"rye config --show-path\", 0);\n  char *rye_config = xy_normalize_path (buf);\n\n  return rye_config;\n}\n\n\n\nvoid\npl_python_rye_getsrc (char *option)\n{\n  char *rye_config = pl_python_find_rye_config ();\n  chsrc_note2 (xy_strcat (3, \"请查看 \", rye_config, \" 配置文件中的 [[sources]] 节内容\"));\n}\n\n\n/**\n * @consult https://github.com/RubyMetric/chsrc/issues/127\n */\nvoid\npl_python_rye_setsrc (char *option)\n{\n  /* 并不在 Python group 中，所以不考虑 target group 情况，仅使用 Python group 提供的源 */\n  Source_t source = chsrc_yield_source_and_confirm (&pl_python_group_target, option);\n\n  const char *content = RAWSTR_pl_python_rye_config;\n\n  content = xy_str_gsub (content, \"@1@\", source.mirror->abbr);\n  content = xy_str_gsub (content, \"@2@\", source.url);\n\n  char *rye_config = pl_python_find_rye_config ();\n  chsrc_note2 (xy_strcat (3, \"请在配置文件 \", rye_config, \" 中添加:\"));\n  println (content);\n\n  chsrc_determine_chgtype (ChgType_Manual);\n  chsrc_conclude (&source);\n}\n\n\nvoid\npl_python_rye_resetsrc (char *option)\n{\n  pl_python_rye_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/Python/common.h",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\n#include \"rawstr4c.h\"\n\ndef_target(pl_python_group, \"python/pypi/py\");\n\n/**\n * @note 测速链接的这个前缀是 ${host}/pipi/web/pacakges/56/e4....\n * 下面有几个镜像站微调了这个路径，我们只要确认能找到 packages 目录就好\n *\n * @note 2025-09-29 更新了测试的 pkg 链接，换用了一个 40M 的文件\n *\n * @warning 2025-09-29 Sjtug 需要特殊处理\n */\nstatic char *\npl_python_speed_url_constructor (const char *url, const char *user_data)\n{\n  char *str = xy_str_delete_suffix (url, \"/simple\");\n  str = xy_2strcat (str, \"/packages/fa/80/eb88edc2e2b11cd2dd2e56f1c80b5784d11d6e6b7f04a1145df64df40065/opencv_python-4.12.0.88-cp37-abi3-win_amd64.whl\");\n  if (strstr (url, \"mirror.sjtu.edu.cn\"))\n    // e.g. https://mirror.sjtu.edu.cn/pypi-packages/fa/80/eb88edc2e2b11cd2dd2e56f1c80b5784d11d6e6b7f04a1145df64df40065/opencv_python-4.12.0.88-cp37-abi3-win_amd64.whl\n    str = xy_str_gsub (str, \"pypi-packages/packages\", \"pypi-packages\");// 针对 Sjtug\n\n  return str;\n}\n\n\nvoid\npl_python_group_prelude (void)\n{\n  chef_prep_this (pl_python_group, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-03\");\n  chef_set_recipe_last_updated (this, \"2025-12-31\");\n  chef_set_sources_last_updated (this, \"2025-09-30\");\n\n  chef_set_chef (this, \"@happy-game\");\n  // 组换源的 leader target 应把所有 follower target 的贡献者都记录过来\n  chef_set_cooks (this, 2, \"@ccmywish\", \"@happy-game\");\n  chef_set_sauciers (this, 3, \"@xyx1926885268\", \"@Kattos\", \"@Mikachu2333\");\n\n  /* 部分包管理器支持 ProjectScope，但是为了让流程执行下去，我们这里都写 ScopeCap_Able_And_Implemented */\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://pypi.org/simple\",                       FeedByPrelude},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/pypi/web/simple\", FeedByPrelude},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/pypi/web/simple\",   FeedByPrelude},\n  // 不要添加Zju，浙大的PyPI服务在校外访问会自动转向Tuna\n  {&Lzuoss,           \"https://mirror.lzu.edu.cn/pypi/web/simple\",     FeedByPrelude},\n  // 2025-09-29 此源已停用\n  // @ref https://mirrors.jlu.edu.cn/_news/#2025-04-06-pypi-repo-down\n  // {&Jlu,              \"https://mirrors.jlu.edu.cn/pypi/web/simple\", FeedByPrelude},\n  {&Sjtug_Siyuan,     \"https://mirror.sjtu.edu.cn/pypi-packages\",      FeedByPrelude},\n  {&Tuna,             \"https://pypi.tuna.tsinghua.edu.cn/simple\",      FeedByPrelude},\n  {&Ali,              \"https://mirrors.aliyun.com/pypi/simple\",        FeedByPrelude},\n  {&Nju,              \"https://mirror.nju.edu.cn/pypi/web/simple\",     FeedByPrelude},\n  {&Pku,              \"https://mirrors.pku.edu.cn/pypi/web/simple\",    FeedByPrelude},\n  {&Tencent,          \"https://mirrors.cloud.tencent.com/pypi/simple\", FeedByPrelude},\n\n  // {&Tencent_Intra, \"https://mirrors.cloud.tencentyun.com/pypi/simple\",FeedByPrelude}\n  {&Huawei,           \"https://mirrors.huaweicloud.com/repository/pypi/simple\",FeedByPrelude},\n  {&Hust,             \"https://mirrors.hust.edu.cn/pypi/web/simple\",FeedByPrelude}\n\n  /* 不启用原因：24小时更新一次 */\n  // {&Netease,       \"https://mirrors.163.com/.help/pypi.html\", NULL}\n  def_sources_end()\n\n  chef_set_rest_smURL_with_func (this, pl_python_speed_url_constructor, NULL);\n}\n\nvoid\npl_python_check_unofficial_pkger (bool *poetry_exist, bool *pdm_exist, bool *uv_exist)\n{\n  *poetry_exist = chsrc_check_program (\"poetry\");\n  *pdm_exist = chsrc_check_program (\"pdm\");\n  *uv_exist = chsrc_check_program (\"uv\");\n}\n\n\n/**\n * @param[out] prog_name 返回 Python 的可用名，如果不可用，则返回 NULL\n */\nvoid\npl_python_get_py_program_name (char **prog_name)\n{\n  *prog_name = NULL;\n\n  bool py_exist = false;\n\n  /**\n   * @issue https://gitee.com/RubyMetric/chsrc/issues/I9VZL2\n   *\n   * 由于Python2和Python3的历史，目前（2024-06）许多python命令实际上仍然是python2\n   * 因此我们首先测试 python3\n   */\n  py_exist = chsrc_check_program (\"python3\");\n\n  if (py_exist)\n    {\n      *prog_name = \"python3\";\n\n      // https://github.com/RubyMetric/chsrc/issues/327\n      if (xy.on_windows)\n        {\n          int status = xy_run_get_status (\"python3 --version\");\n          if (status == 9009)\n            {\n              chsrc_error2 (CHINESE ? \"用户环境中的 `python3` 命令，是微软商店的占位符，并非真正可用的 Python。请安装真正的 Python 后重试！\"\n                                    : \"`python3` in your environment is a placeholder of Microsoft Store, not the real Python which can be used, please install the real Python and try again!\");\n              exit (Exit_UserCause);\n            }\n        }\n\n    }\n  else\n    {\n      /**\n       * 不要直接:\n       *\n       *   $ python\n       *\n       * 这样调用 `python` 自己，而是使用 `python --version`，或者其他方式\n       * 因为直接执行 `python` 会使 Windows 弹出Microsoft Store\n       */\n      py_exist = chsrc_check_program (\"python\");\n\n      if (py_exist) *prog_name = \"python\";\n      else\n        {\n          chsrc_error (\"未找到 Python 相关命令，请检查是否存在\");\n          exit (Exit_UserCause);\n        }\n    }\n}\n"
  },
  {
    "path": "src/recipe/lang/Python/pip.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_python_pip, \"pip\");\n\nvoid\npl_python_pip_prelude (void)\n{\n  chef_prep_this (pl_python_pip, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-03\");\n  chef_set_recipe_last_updated (this, \"2025-09-12\");\n  chef_set_sources_last_updated (this, \"2025-07-11\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@happy-game\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  chef_use_other_target_sources (this, &pl_python_group_target);\n}\n\n\nvoid\npl_python_pip_getsrc (char *option)\n{\n  char *py_prog_name = NULL;\n  pl_python_get_py_program_name (&py_prog_name);\n\n  char *cmd = xy_2strcat (py_prog_name, \" -m pip config get global.index-url\");\n\n  int status = chsrc_run_directly (cmd);\n  if (0 == status)\n    {\n      // 执行成功时显示当前源\n      xy_noop ();\n    }\n  else\n    {\n      // 执行失败时显示默认源\n      if (ENGLISH)\n        chsrc_note2 (\"No source configured in pip, showing default upstream source:\");\n      else\n        chsrc_note2 (\"pip 中未配置源，显示默认上游源：\");\n\n      Source_t default_source = chsrc_yield_source (&pl_python_group_target, \"upstream\");\n      say (default_source.url);\n    }\n}\n\n\n/**\n * @consult https://mirrors.tuna.tsinghua.edu.cn/help/pypi/\n */\nvoid\npl_python_pip_setsrc (char *option)\n{\n  // 对于不支持的情况，尽早结束\n  if (chsrc_in_project_scope_mode())\n    {\n      char *msg = ENGLISH ? \"pip doesn't support `-scope=project`. SKIP changing source!\"\n                          : \"pip 不支持项目级换源，跳过换源\";\n      chsrc_error (msg);\n      // 不能直接退出，因为 Leader target 不能就此结束\n      return;\n    }\n\n  Source_t source = chsrc_yield_source (&pl_python_group_target, option);\n  if (chsrc_in_standalone_mode())\n    chsrc_confirm_source(&source);\n\n  char *py_prog_name = NULL;\n  pl_python_get_py_program_name (&py_prog_name);\n\n  // 这里用的是 config --user，会写入用户目录（而不是项目目录）\n  // https://github.com/RubyMetric/chsrc/issues/39\n  // 经测试，Windows上调用换源命令，会写入 C:\\Users\\RubyMetric\\AppData\\Roaming\\pip\\pip.ini\n  char *cmd = xy_2strcat (py_prog_name, xy_2strcat (\" -m pip config --user set global.index-url \", source.url));\n  chsrc_run (cmd, RunOpt_No_Last_New_Line);\n\n  if (chsrc_in_standalone_mode())\n    {\n      chsrc_determine_chgtype (ChgType_Auto);\n      chsrc_conclude (&source);\n    }\n}\n\n\nvoid\npl_python_pip_resetsrc (char *option)\n{\n  pl_python_pip_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/Python/rawstr4c.h",
    "content": "#pragma once\n\n/**\n * Generated by rawstr4c v1.1.0-2025/09/27\n */\n\nchar RAWSTR_pl_python_uv_config_source_content[] = \"\\x5b\\x5b\\x69\\x6e\\x64\\x65\\x78\\x5d\\x5d\\x0a\\x75\\x72\\x6c\\x20\\x3d\\x20\\x22\\x40\\x75\\x72\\x6c\\x40\\x22\\x0a\\x64\\x65\\x66\\x61\\x75\\x6c\\x74\\x20\\x3d\\x20\\x74\\x72\\x75\\x65\\x0a\";\n\nchar RAWSTR_pl_python_get_uv_config[] = \"\\x67\\x72\\x65\\x70\\x20\\x2d\\x41\\x20\\x32\\x20\\x27\\x69\\x6e\\x64\\x65\\x78\\x27\\x20\\x40\\x66\\x40\\x20\\x7c\\x20\\x73\\x65\\x64\\x20\\x2d\\x6e\\x20\\x27\\x73\\x2f\\x5e\\x75\\x72\\x6c\\x20\\x3d\\x20\\x22\\x5c\\x28\\x2e\\x2a\\x5c\\x29\\x22\\x2f\\x5c\\x31\\x2f\\x70\\x27\";\n\nchar RAWSTR_pl_python_get_uv_config_on_windows[] = \"\\x24\\x6c\\x69\\x6e\\x65\\x73\\x20\\x3d\\x20\\x47\\x65\\x74\\x2d\\x43\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x20\\x40\\x66\\x40\\x3b\\x0a\\x0a\\x66\\x6f\\x72\\x28\\x24\\x69\\x6e\\x64\\x65\\x78\\x3d\\x30\\x3b\\x20\\x24\\x69\\x6e\\x64\\x65\\x78\\x20\\x2d\\x6c\\x74\\x20\\x24\\x6c\\x69\\x6e\\x65\\x73\\x2e\\x43\\x6f\\x75\\x6e\\x74\\x3b\\x20\\x24\\x69\\x6e\\x64\\x65\\x78\\x2b\\x2b\\x29\\x20\\x7b\\x0a\\x20\\x20\\x69\\x66\\x28\\x24\\x6c\\x69\\x6e\\x65\\x73\\x5b\\x24\\x69\\x6e\\x64\\x65\\x78\\x5d\\x20\\x2d\\x6d\\x61\\x74\\x63\\x68\\x20\\x27\\x5e\\x5c\\x5b\\x5c\\x5b\\x69\\x6e\\x64\\x65\\x78\\x5c\\x5d\\x5c\\x5d\\x24\\x27\\x29\\x20\\x7b\\x0a\\x20\\x20\\x20\\x20\\x24\\x6c\\x69\\x6e\\x65\\x73\\x5b\\x24\\x69\\x6e\\x64\\x65\\x78\\x2e\\x2e\\x28\\x24\\x69\\x6e\\x64\\x65\\x78\\x2b\\x33\\x29\\x5d\\x0a\\x20\\x20\\x7d\\x0a\\x7d\";\n\nchar RAWSTR_pl_python_set_uv_config[] = \"\\x40\\x73\\x65\\x64\\x40\\x20\\x27\\x2f\\x5e\\x5c\\x5b\\x5c\\x5b\\x69\\x6e\\x64\\x65\\x78\\x5c\\x5d\\x5c\\x5d\\x24\\x2f\\x2c\\x2f\\x5e\\x64\\x65\\x66\\x61\\x75\\x6c\\x74\\x20\\x3d\\x20\\x74\\x72\\x75\\x65\\x24\\x2f\\x7b\\x73\\x7c\\x5e\\x75\\x72\\x6c\\x20\\x3d\\x20\\x22\\x2e\\x2a\\x22\\x24\\x7c\\x75\\x72\\x6c\\x20\\x3d\\x20\\x22\\x40\\x75\\x72\\x6c\\x40\\x22\\x7c\\x3b\\x7d\\x27\\x20\\x40\\x66\\x40\";\n\nchar RAWSTR_pl_python_set_uv_config_on_windows[] = \"\\x70\\x6f\\x77\\x65\\x72\\x73\\x68\\x65\\x6c\\x6c\\x20\\x2d\\x43\\x6f\\x6d\\x6d\\x61\\x6e\\x64\\x20\\x22\\x24\\x63\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x20\\x3d\\x20\\x47\\x65\\x74\\x2d\\x43\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x20\\x27\\x40\\x66\\x40\\x27\\x3b\\x20\\x24\\x63\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x20\\x3d\\x20\\x24\\x63\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x20\\x2d\\x72\\x65\\x70\\x6c\\x61\\x63\\x65\\x20\\x27\\x5e\\x75\\x72\\x6c\\x20\\x3d\\x20\\x5c\\x22\\x2e\\x2a\\x5c\\x22\\x24\\x27\\x2c\\x20\\x27\\x75\\x72\\x6c\\x20\\x3d\\x20\\x5c\\x22\\x40\\x75\\x72\\x6c\\x40\\x5c\\x22\\x27\\x3b\\x20\\x24\\x63\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x20\\x7c\\x20\\x53\\x65\\x74\\x2d\\x43\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x20\\x27\\x40\\x66\\x40\\x27\\x22\";\n\nchar RAWSTR_pl_python_test_uv_if_set_source[] = \"\\x67\\x72\\x65\\x70\\x20\\x2d\\x71\\x20\\x27\\x5e\\x5c\\x5b\\x5c\\x5b\\x69\\x6e\\x64\\x65\\x78\\x5d\\x5d\\x24\\x27\\x20\\x40\\x66\\x40\";\n\nchar RAWSTR_pl_python_test_uv_if_set_source_on_windows[] = \"\\x70\\x6f\\x77\\x65\\x72\\x73\\x68\\x65\\x6c\\x6c\\x20\\x2d\\x43\\x6f\\x6d\\x6d\\x61\\x6e\\x64\\x20\\x22\\x69\\x66\\x20\\x28\\x47\\x65\\x74\\x2d\\x43\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x20\\x40\\x66\\x40\\x20\\x7c\\x20\\x53\\x65\\x6c\\x65\\x63\\x74\\x2d\\x53\\x74\\x72\\x69\\x6e\\x67\\x20\\x27\\x5e\\x5c\\x5b\\x5c\\x5b\\x69\\x6e\\x64\\x65\\x78\\x5c\\x5d\\x5c\\x5d\\x24\\x27\\x29\\x20\\x7b\\x20\\x65\\x78\\x69\\x74\\x20\\x30\\x20\\x7d\\x20\\x65\\x6c\\x73\\x65\\x20\\x7b\\x20\\x65\\x78\\x69\\x74\\x20\\x31\\x20\\x7d\\x22\";\n\nchar RAWSTR_pl_python_rye_config[] = \"\\x5b\\x5b\\x73\\x6f\\x75\\x72\\x63\\x65\\x73\\x5d\\x5d\\x0a\\x6e\\x61\\x6d\\x65\\x20\\x3d\\x20\\x22\\x40\\x31\\x40\\x22\\x0a\\x75\\x72\\x6c\\x20\\x20\\x3d\\x20\\x22\\x40\\x32\\x40\\x22\";\n\n"
  },
  {
    "path": "src/recipe/lang/Python/rawstr4c.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------------------------------------------------------------\n ! Config Type   : rawstr4c (Markdown)\n ! Config Authors: @ccmywish\n !               | @happy-game\n !               | @MingriLingran\n ! Contributors  :  Nil Null <nil@null.org>\n ! Created On    : <2025-07-14>\n ! Last Modified : <2025-12-29>\n ! ---------------------------------------------------------- -->\n\n# rawstr4c input for Python\n\n- prefix = `RAWSTR_pl_python`\n- output = `:global-variable-only-header`\n- translate = `:hex`\n- no-postfix = `true`\n\n<br>\n\n\n\n## uv\n\n### uv config source content\n\n```toml\n[[index]]\nurl = \"@url@\"\ndefault = true\n\n```\n\n\n### Get uv config\n\n```sh\ngrep -A 2 'index' @f@ | sed -n 's/^url = \"\\(.*\\)\"/\\1/p'\n```\n\n\n### Get uv config on Windows\n\n为什么不用 `Select-String`，原因见: <https://github.com/RubyMetric/chsrc/pull/328#issuecomment-3695577870>\n\n还有另外一个好处：如果 `[[index]]` 配置被写入了多次，可以这样检查出来\n\n我们倾向于使用脚本而非命令，因为内容较长，便于用户检查到底执行了什么内容。\n\n```powershell\n$lines = Get-Content @f@;\n\nfor($index=0; $index -lt $lines.Count; $index++) {\n  if($lines[$index] -match '^\\[\\[index\\]\\]$') {\n    $lines[$index..($index+3)]\n  }\n}\n```\n\n\n### Set uv config\n\n```sh\n@sed@ '/^\\[\\[index\\]\\]$/,/^default = true$/{s|^url = \".*\"$|url = \"@url@\"|;}' @f@\n```\n\n### Set uv config on Windows\n\n```powershell\npowershell -Command \"$content = Get-Content '@f@'; $content = $content -replace '^url = \\\".*\\\"$', 'url = \\\"@url@\\\"'; $content | Set-Content '@f@'\"\n```\n\n\n### Test uv if set source\n\n```sh\ngrep -q '^\\[\\[index]]$' @f@\n```\n\n### Test uv if set source on Windows\n\n```powershell\npowershell -Command \"if (Get-Content @f@ | Select-String '^\\[\\[index\\]\\]$') { exit 0 } else { exit 1 }\"\n```\n\n<br>\n\n\n\n## Rye\n\n- name = `rye_config`\n\n```toml\n[[sources]]\nname = \"@1@\"\nurl  = \"@2@\"\n```\n"
  },
  {
    "path": "src/recipe/lang/Python/uv.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_python_uv, \"uv\");\n\nvoid\npl_python_uv_prelude (void)\n{\n  chef_prep_this (pl_python_uv, gsr);\n\n  chef_set_recipe_created_on   (this, \"2024-12-11\");\n  chef_set_recipe_last_updated (this, \"2025-12-29\");\n  chef_set_sources_last_updated (this, \"2025-08-09\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 2, \"@happy-game\", \"@MingriLingran\");\n  chef_set_sauciers (this, 2, \"@Kattos\", \"@ccmywish\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Able_But_Not_Implemented);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  chef_use_other_target_sources (this, &pl_python_group_target);\n}\n\n\n/**\n * chsrc get uv\n *\n * uv的配置优先级顺序如下(高到低):\n * 1. $workspaces/uv.toml\n * 2. $workspaces/pyproject.toml\n * 3. ~/.config/uv/uv.toml\n * 4. /etc/uv/uv.toml\n */\n\n#define PL_Python_uv_ConfigFile       \"uv.toml\"\n#define PL_Python_uv_Local_ConfigPath \"./\"\n#define PL_Python_uv_User_ConfigPath  \"~/.config/uv/\"\n\n\nchar *\npl_python_find_uv_config (bool mkdir)\n{\n  if (chsrc_in_project_scope_mode())\n    {\n      return xy_2strcat (PL_Python_uv_Local_ConfigPath, PL_Python_uv_ConfigFile);\n    }\n  else\n    {\n      if (xy.on_windows)\n        {\n          /* config path on Windows */\n          char *appdata = getenv (\"APPDATA\");\n\n          if (!appdata)\n            {\n              chsrc_error2 (\"未能获取 APPDATA 环境变量\");\n              return NULL;\n            }\n\n          char *config_dir = xy_2strcat(appdata, \"\\\\uv\\\\\");\n          if (mkdir)\n            {\n              chsrc_ensure_dir (config_dir);\n            }\n          return xy_2strcat (config_dir, PL_Python_uv_ConfigFile);\n        }\n      else\n        {\n          /* config path on Linux or macOS */\n          if (mkdir)\n            {\n              chsrc_ensure_dir (PL_Python_uv_User_ConfigPath);\n            }\n          return xy_2strcat (PL_Python_uv_User_ConfigPath, PL_Python_uv_ConfigFile);\n        }\n    }\n}\n\nvoid\npl_python_uv_getsrc (char *option)\n{\n  char *uv_config = pl_python_find_uv_config (false);\n\n  if (!chsrc_check_file (uv_config))\n    {\n      chsrc_error2 (\"未找到 uv 配置文件\");\n      return;\n    }\n\n  /* 获取 [[index]] 配置项的 url */\n  if (xy.on_windows)\n    {\n      /* 在 Windows 上使用 PowerShell 替代 grep */\n      char *script = xy_str_gsub (RAWSTR_pl_python_get_uv_config_on_windows, \"@f@\", uv_config);\n      chsrc_run_as_powershell_file (script);\n    }\n  else\n    {\n      /* 在类 Unix 系统上使用 grep */\n      char *cmd = xy_str_gsub (RAWSTR_pl_python_get_uv_config, \"@f@\", uv_config);\n      chsrc_run (cmd, RunOpt_Default);\n    }\n}\n\n\n/**\n * @consult https://docs.astral.sh/uv/configuration/files/\n *          https://github.com/RubyMetric/chsrc/issues/139\n */\nvoid\npl_python_uv_setsrc (char *option)\n{\n  chsrc_ensure_program (\"uv\");\n\n  Source_t source = chsrc_yield_source (&pl_python_group_target, option);\n  if (chsrc_in_standalone_mode())\n    chsrc_confirm_source(&source);\n\n  char *uv_config = pl_python_find_uv_config (true);\n  if (NULL==uv_config)\n    {\n      chsrc_error2 (\"无法获取 uv 配置文件路径\");\n      return;\n    }\n  chsrc_backup (uv_config);\n\n  const char *source_content = xy_str_gsub (RAWSTR_pl_python_uv_config_source_content, \"@url@\", source.url);\n\n  if (!xy_file_exist (uv_config))\n    {\n      /* 当 uv_config 不存在，直接写入文件 */\n      chsrc_append_to_file (source_content, uv_config);\n    }\n  else\n    {\n      /* 当 uv_config 存在，如果存在 [[index]] 则更新，否则追加到文件末尾 */\n      char *cmd = NULL;\n      if (xy.on_windows)\n        {\n          /* 在 Windows 上使用 PowerShell 替代 grep */\n          cmd = xy_str_gsub (RAWSTR_pl_python_test_uv_if_set_source_on_windows, \"@f@\", uv_config);\n        }\n      else\n        {\n          cmd = xy_str_gsub (RAWSTR_pl_python_test_uv_if_set_source, \"@f@\", uv_config);\n        }\n\n      int status = xy_run_get_status (cmd);\n      if (0==status)\n        {\n          if (xy.on_windows)\n            {\n              /* 在 Windows 上使用 PowerShell 替代 sed */\n              char *powershell_cmd_with_file = xy_str_gsub(RAWSTR_pl_python_set_uv_config_on_windows, \"@f@\", uv_config);\n              char *powershell_cmd = xy_str_gsub(powershell_cmd_with_file, \"@url@\", source.url);\n              chsrc_run (powershell_cmd, RunOpt_Default);\n            }\n          else\n            {\n              /* 非 Windows 系统使用 sed */\n              char *sed_cmd = NULL;\n#if defined(XY_Build_On_macOS) || defined(XY_Build_On_BSD)\n              sed_cmd = \"sed -i '' \";\n#else\n              sed_cmd = \"sed -i \";\n#endif\n              char *update_config_cmd = xy_str_gsub (RAWSTR_pl_python_set_uv_config, \"@sed@\", sed_cmd);\n                    update_config_cmd = xy_str_gsub (update_config_cmd, \"@f@\", uv_config);\n                    update_config_cmd = xy_str_gsub (update_config_cmd, \"@url@\", source.url);\n              chsrc_run (update_config_cmd, RunOpt_Default);\n            }\n        }\n      else\n        {\n          chsrc_append_to_file (source_content, uv_config);\n        }\n    }\n\n  if (chsrc_in_standalone_mode())\n    {\n      chsrc_determine_chgtype (ChgType_Auto);\n      chsrc_conclude (&source);\n    }\n}\n\n\nvoid\npl_python_uv_resetsrc (char *option)\n{\n  pl_python_uv_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/R.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_r, \"r/cran\");\n\nvoid\npl_r_prelude ()\n{\n  chef_prep_this (pl_r, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-21\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-08-21\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@hezonglun\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unknown);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unknown);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  // 以下注释的，是不含有bioconductor的镜像站，我们在换cran的同时，也直接帮助用户换bioconductor\n  def_sources_begin()\n  {&UpstreamProvider, \"https://cran.r-project.org/\", DelegateToUpstream},\n  {&Sjtug_Zhiyuan,    \"https://mirrors.sjtug.sjtu.edu.cn/cran/\",    DelegateToMirror},\n  // {&Ali,           \"https://mirrors.aliyun.com/CRAN/\",           DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/CRAN/\", DelegateToMirror},\n  // {&Sustech,       \"https://mirrors.sustech.edu.cn/CRAN\",        DelegateToMirror},\n  // {&Bfsu,          \"https://mirrors.bfsu.edu.cn/CRAN/\",          DelegateToMirror},\n  // {&Bjtu,          \"https://mirror.bjtu.edu.cn/cran/\",           DelegateToMirror},\n  def_sources_end()\n}\n\n\n#define PL_R_Config_Windows \"~/Documents/.Rprofile\"\n#define PL_R_Config_POSIX   \"~/.Rprofile\"\n\nvoid\npl_r_getsrc (char *option)\n{\n  /**\n   * 或参考：https://zhuanlan.zhihu.com/p/585036231\n   *\n   * options()$repos\n   * options()$BioC_mirror\n   */\n  if (xy.on_windows)\n    {\n      chsrc_view_file (PL_R_Config_Windows);\n    }\n  else\n    {\n      chsrc_view_file (PL_R_Config_POSIX);\n    }\n}\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/CRAN/\n */\nvoid\npl_r_setsrc (char *option)\n{\n  chsrc_use_this_source (pl_r);\n\n  char *bioconductor_url = xy_str_delete_suffix (xy_str_delete_suffix (source.url, \"cran/\"), \"CRAN/\");\n  bioconductor_url = xy_2strcat(bioconductor_url, \"bioconductor\");\n\n  const char *w1 = xy_strcat (3, \"options(\\\"repos\\\" = c(CRAN=\\\"\", source.url, \"\\\"))\\n\" );\n  const char *w2 = xy_strcat (3, \"options(BioC_mirror=\\\"\", bioconductor_url, \"\\\")\\n\" );\n\n  char *w = xy_2strcat (w1, w2);\n\n  // 或者我们调用 r.exe --slave -e 上面的内容\n\n  char *config = xy.on_windows ? PL_R_Config_Windows : PL_R_Config_POSIX;\n\n  chsrc_append_to_file (w, config);\n\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/lang/Ruby/README.md",
    "content": "# Ruby 换源问题\n\nhttps://github.com/ustclug/discussions/issues/438\n\n\n- 清华、北京外国语: 不可用，原因是: 实现不足 https://github.com/tuna/issues/issues/374\n\n- 腾讯: 不可用，原因是:  缺乏 `versions` 文件\n- 阿里: 不可用，原因是:  缺乏 `versions` 文件\n\n- 华为: 不可用，原因是：版本太过老旧，应该是没有同步\n"
  },
  {
    "path": "src/recipe/lang/Ruby/Ruby.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\nstatic MirrorSite_t RubyChina =\n{\n  IS_DedicatedMirrorSite,\n  \"rubychina\", \"RubyChina\", \"Ruby China 社区\", \"https://gems.ruby-china.com/\",\n  {NotSkip, NA, NA, \"https://gems.ruby-china.com/rubygems/gems/nokogiri-1.15.0-java.gem\", ACCURATE} // 9.9 MB\n};\n\ndef_target(pl_ruby, \"gem/ruby/rb/rubygem/rubygems/bundler\");\n\nvoid\npl_ruby_prelude (void)\n{\n  chef_prep_this (pl_ruby, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-08-29\");\n  chef_set_recipe_last_updated (this, \"2025-08-11\");\n  chef_set_sources_last_updated (this, \"2024-12-18\");\n\n  chef_set_chef (this, \"@ccmywish\");\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@BingChunMoLi\");\n\n  /* 支持 bundler. 不支持 gem */\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://rubygems.org/\",        \"https://rubygems.org/gems/nokogiri-1.15.0-java.gem\"},\n  {&RubyChina,        \"https://gems.ruby-china.com/\",                   DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/rubygems/\",          DelegateToMirror}\n  // {&Tuna,          \"https://mirrors.tuna.tsinghua.edu.cn/rubygems/\", DelegateToMirror},\n  // {&Bfsu,          \"https://mirrors.bfsu.edu.cn/rubygems/\",          DelegateToMirror},\n\n  // {&Tencent,       \"https://mirrors.tencent.com/rubygems/\",                DelegateToMirror},\n  // {&Tencent_Intra, \"https://mirrors.tencentyun.com/rubygems/\",             DelegateToMirror},\n  // {&Ali,           \"https://mirrors.aliyun.com/rubygems/\",                 DelegateToMirror},\n  // {&Huawei,        \"https://mirrors.huaweicloud.com/repository/rubygems/\", DelegateToMirror},\n  def_sources_end()\n}\n\n\nvoid\npl_ruby_getsrc (char *option)\n{\n  chsrc_run (\"gem sources\", RunOpt_Default);\n  chsrc_run (\"bundle config get mirror.https://rubygems.org\", RunOpt_Default);\n}\n\nbool\npl_ruby_remove_gem_source (const char *source)\n{\n  char *cmd = NULL;\n  if (hp_is_url (source))\n    {\n      cmd = xy_2strcat (\"gem sources -r \", source);\n      chsrc_run (cmd, RunOpt_Default);\n    }\n  return false;\n}\n\n/**\n * @consult https://gitee.com/RubyMetric/rbenv-cn\n */\nvoid\npl_ruby_setsrc (char *option)\n{\n  chsrc_ensure_program (\"gem\");\n\n  chsrc_use_this_source (pl_ruby);\n\n  char *cmd = NULL;\n\n  // step1\n  xy_run_iter_lines (\"gem sources -l\", 0, pl_ruby_remove_gem_source);\n\n  cmd = xy_2strcat (\"gem source -a \", source.url);\n  chsrc_run (cmd, RunOpt_Default);\n\n  // 我们在 step1 中，把源全部清空了，但是现在 RubyGems 的行为是: 当清空会自动给你把默认源给加回来\n  // 所以我们在这一步，最后一次删除默认源，确保它不存在\n  pl_ruby_remove_gem_source (this->sources[0].url);\n\n\n  chsrc_ensure_program (\"bundle\");\n\n  char *where = \" --global \";\n  if (chsrc_in_project_scope_mode())\n    {\n      where = \" --local \";\n    }\n\n  cmd = xy_strcat (4, \"bundle config\", where, \"'mirror.https://rubygems.org' \", source.url);\n  chsrc_run (cmd, RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\nvoid\npl_ruby_resetsrc (char *option)\n{\n  pl_ruby_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/Rust/Cargo.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(pl_rust_cargo, \"rust/cargo/crate/crates\");\n\nvoid\npl_rust_cargo_prelude (void)\n{\n  chef_prep_this (pl_rust_cargo, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-08-30\");\n  chef_set_recipe_last_updated (this, \"2025-12-31\");\n  chef_set_sources_last_updated (this, \"2026-01-21\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 2, \"@Mikachu2333\", \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@happy-game\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_But_Not_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english (this);\n  chef_allow_user_define (this);\n\n\n  // 以下都支持稀疏索引，我们换源时都将默认添加 `sparse+`。链接末尾的 `/` 不能缺少\n  /**\n   * @warning 2025-12-29:\n   *   许多镜像站的 dl 字段指向 static.crates.io，因此测速链接也指向 static.crates.io，原API失效\n   *   见: https://github.com/RubyMetric/chsrc/pull/330\n   */\n#define url_postfix \"api/v1/crates/windows/0.62.2/download\"\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://crates.io/\",                             \"https://static.crates.io/crates/windows/windows-0.62.2.crate\"},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/crates.io-index/\", NULL},\n  {&RsProxyCN,        \"https://rsproxy.cn/index/\",                      \"https://rsproxy.cn/\" url_postfix},\n  {&Ali,              \"https://mirrors.aliyun.com/crates.io-index/\",    \"https://mirrors.aliyun.com/crates/\" url_postfix},\n  {&Zju,              \"https://mirrors.zju.edu.cn/crates.io-index/\",    NULL},\n\n  /* 注释原因: (2025-06-17) 镜像同步失败，多数包都不可用 */\n  // {&Nju,        \"https://mirror.nju.edu.cn/git/crates.io-index.git/\",   FeedByPrelude},\n\n  {&Sjtug_Zhiyuan, \"https://mirrors.sjtug.sjtu.edu.cn/crates.io-index/\",   \"https://mirror.sjtu.edu.cn/crates.io/crates/windows/windows-0.58.0.crate\"},\n  {&Tuna,          \"https://mirrors.tuna.tsinghua.edu.cn/crates.io-index/\", NULL},\n  {&Bfsu,          \"https://mirrors.bfsu.edu.cn/crates.io-index/\",          NULL},\n  {&Ustc,          \"https://mirrors.ustc.edu.cn/crates.io-index/\",         \"https://crates-io.proxy.ustclug.org/\" url_postfix},\n\n  /* 注释原因: (2025-06-17) 镜像同步失败，多数包都不可用 */\n  // {&Hust,       \"https://mirrors.hust.edu.cn/crates.io-index/\", FeedByPrelude},\n\n  {&Cqu,           \"https://mirrors.cqu.edu.cn/crates.io-index/\",  NULL}\n  def_sources_end()\n\n#undef url_postfix\n}\n\n\nvoid\npl_rust_cargo_note_get_src_default ()\n{\n  if (ENGLISH)\n    chsrc_note2 (\"No source configured in Cargo, showing default upstream source:\");\n  else\n    chsrc_note2 (\"Cargo 中未自定义源，显示默认源：\");\n\n    Source_t default_source = chsrc_yield_source (&pl_rust_cargo_target, \"upstream\");\n    say (default_source.url);\n}\n\nvoid\npl_rust_cargo_note_get_src_mirror (char *url, bool sparse)\n{\n  chsrc_note2 (ENGLISH ? \"Custom source found: \" : \"已找到自定义源：\");\n  say (xy_2strcat (url, sparse ? \" (sparse)\" : \"\"));\n}\n\nvoid\npl_rust_cargo_getsrc (char *option)\n{\n  char *cargo_config_file = xy_normalize_path (\"~/.cargo/config.toml\");\n\n  char *raw_content = xy_file_read (cargo_config_file);\n  char *formatted_content = xy_str_gsub (raw_content, \" \", \"\");\n  formatted_content = xy_str_gsub (formatted_content, \"'\", \"\\\"\");\n\n  XyStrFindResult_t result_has_mirror = xy_str_find (formatted_content, \"replace-with\");\n  if (result_has_mirror.found)\n    {\n      char *mirror_name = xy_str_next_nonempty_line (formatted_content + result_has_mirror.end + 1);\n      mirror_name = xy_str_delete_prefix (mirror_name, \"=\\\"\");\n      mirror_name = xy_str_delete_suffix (mirror_name, \"\\\"\");\n\n      XyStrFindResult_t result_mirror = xy_str_find (formatted_content, xy_strcat (3, \"[source.\", mirror_name, \"]\"));\n      if (!result_mirror.found)\n        {\n          pl_rust_cargo_note_get_src_default();\n          return;\n        }\n      char *mirror_url = xy_str_next_nonempty_line (formatted_content + result_mirror.end + 1);\n      mirror_url = xy_str_delete_prefix (mirror_url, \"registry=\\\"\");\n      mirror_url = xy_str_delete_suffix (mirror_url, \"\\\"\");\n      if (xy_str_find (mirror_url, \"sparse+\").found)\n        {\n          pl_rust_cargo_note_get_src_mirror (xy_str_delete_prefix (mirror_url, \"sparse+\"), true);\n        }\n    }\n  else\n    {\n      pl_rust_cargo_note_get_src_default();\n    }\n}\n\n\nvoid\npl_write_rust_config (const char *path, const char *url)\n{\n  remove (path);\n  char *content = RAWSTR_pl_rust_cargo_config;\n  content = xy_str_gsub (content, \"@url@\", url);\n  chsrc_overwrite_file (content, path);\n}\n\n/**\n * @consult https://mirrors.tuna.tsinghua.edu.cn/help/crates.io-index/\n * @consult https://help.mirrors.cernet.edu.cn/crates.io-index\n */\nvoid\npl_rust_cargo_setsrc (char *option)\n{\n  chsrc_ensure_program (\"cargo\");\n\n  chsrc_use_this_source (pl_rust_cargo);\n\n  char *default_content = RAWSTR_pl_rust_cargo_config;\n  char *cargo_config_dir = \"~/.cargo/\";\n  char *cargo_config_file = xy_2strcat (cargo_config_dir, \"config.toml\");\n\n  chsrc_ensure_dir (cargo_config_dir);\n\n  cargo_config_file = xy_normalize_path (cargo_config_file);\n\n  if (xy_file_exist (cargo_config_file))\n    {\n      chsrc_backup (cargo_config_file);\n\n      char *raw_content = xy_file_read (cargo_config_file);\n\n      XyStrFindResult_t result_has_mirror = xy_str_find (raw_content, \"replace-with\");\n      if (!result_has_mirror.found)\n        {\n          pl_write_rust_config (cargo_config_file, source.url);\n          goto finish;\n        }\n\n      char *mirror_name = xy_str_next_nonempty_line (raw_content + result_has_mirror.end + 1);\n      mirror_name = xy_str_gsub (mirror_name, \" \", \"\");\n      mirror_name = xy_str_gsub (mirror_name, \"'\", \"\\\"\");\n      mirror_name = xy_str_delete_prefix (mirror_name, \"=\\\"\");\n      mirror_name = xy_str_delete_suffix (mirror_name, \"\\\"\");\n\n      XyStrFindResult_t result_mirror = xy_str_find (raw_content, xy_strcat (3, \"[source.\", mirror_name, \"]\"));\n      if (!result_mirror.found)\n        {\n          pl_write_rust_config (cargo_config_file, source.url);\n          goto finish;\n        }\n\n      char *mirror_url = xy_str_next_nonempty_line (raw_content + result_mirror.end + 1);\n      mirror_url = xy_str_gsub (mirror_url, \" \", \"\");\n      if (!xy_str_find (mirror_url, \"registry\").found)\n        {\n          pl_write_rust_config (cargo_config_file, source.url);\n          goto finish;\n        }\n      mirror_url = xy_str_delete_prefix (mirror_url, \"registry=\\\"\");\n      mirror_url = xy_str_delete_suffix (mirror_url, \"\\\"\");\n\n      char *final_content = xy_str_gsub (raw_content, mirror_url, xy_2strcat (\"sparse+\", source.url));\n      chsrc_overwrite_file (final_content, cargo_config_file);\n      goto finish;\n    }\n\n    pl_write_rust_config (cargo_config_file, source.url);\n    goto finish;\n\nfinish:\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\npl_rust_cargo_resetsrc (char *option)\n{\n  pl_rust_cargo_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/Rust/common.h",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Authors  : Aoran Zeng <ccmywish@qq.com>\n * Contributors  :  Nil Null  <nil@null.org>\n * Created On    : <2024-10-02>\n * Last Modified : <2025-07-11>\n * ------------------------------------------------------------*/\n\nstatic MirrorSite_t RsProxyCN =\n{\n  IS_DedicatedMirrorSite,\n  \"rsproxycn\", \"RsProxy.cn\", \"字节跳动基础架构Dev Infra\", \"https://rsproxy.cn/\",\n  {NotSkip, NA, NA, \"https://rsproxy.cn/api/v1/crates/windows/0.58.0/download\", ACCURATE}\n};\n"
  },
  {
    "path": "src/recipe/lang/Rust/rustup.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\n// Size: 20MB\n#define PL_Rustup_Speed_URL_Suffix\n\ndef_target(pl_rust_rustup, \"rustup\");\n\nvoid\npl_rust_rustup_prelude (void)\n{\n  chef_prep_this (pl_rust_rustup, gsr);\n\n  chef_set_recipe_created_on   (this, \"2024-10-02\");\n  chef_set_recipe_last_updated (this, \"2025-08-07\");\n  chef_set_sources_last_updated (this, \"2025-08-07\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 2, \"@Yangmoooo\", \"@Mikachu2333\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english (this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://static.rust-lang.org\",                 FeedByPrelude},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/rustup\",         FeedByPrelude},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/rustup\",  FeedByPrelude},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/rust-static\",      FeedByPrelude},\n  {&Nju,              \"https://mirror.nju.edu.cn/rustup\",             FeedByPrelude},\n  {&Sjtug_Zhiyuan,    \"https://mirror.sjtu.edu.cn/rust-static\",       FeedByPrelude},\n  {&Zju,              \"https://mirrors.zju.edu.cn/rustup\",            FeedByPrelude},\n  {&Iscas,            \"https://mirror.iscas.ac.cn/rustup\",            FeedByPrelude},\n  {&Ali,              \"https://mirrors.aliyun.com/rustup\",            FeedByPrelude},\n  {&RsProxyCN,        \"https://rsproxy.cn\",                           FeedByPrelude}\n  def_sources_end()\n\n  // 20MB大小\n  chef_set_rest_smURL_with_postfix (this, \"/dist/2025-06-26/cargo-1.88.0-x86_64-unknown-illumos.tar.gz\");\n}\n\n\n\nvoid\npl_rust_rustup_getsrc (char *option)\n{\n  chsrc_view_env (\"RUSTUP_UPDATE_ROOT\", \"RUSTUP_DIST_SERVER\", NULL);\n}\n\n\n/**\n * @consult https://mirrors.tuna.tsinghua.edu.cn/help/rustup/\n */\nvoid\npl_rust_rustup_setsrc (char *option)\n{\n  chsrc_use_this_source (pl_rust_rustup);\n\n#ifdef XY_Build_On_Windows\n\n  char *cmd1 = xy_strcat (3, \"setx RUSTUP_DIST_SERVER \\\"\", source.url, \"\\\"\");\n  char *cmd2 = xy_strcat (3, \"setx RUSTUP_UPDATE_ROOT \\\"\", source.url, \"/rustup\\\"\");\n\n  char *cmd = xy_strcat (3, cmd1, \" & \", cmd2);\n  chsrc_run (cmd, RunOpt_Dont_Notify_On_Success|RunOpt_No_Last_New_Line);\n\n#else\n\n  char *w1 = xy_strcat (3, \"export RUSTUP_DIST_SERVER=\\\"\", source.url, \"\\\"\\n\");\n  char *w2 = xy_strcat (3, \"export RUSTUP_UPDATE_ROOT=\\\"\", source.url, \"/rustup\\\"\\n\");\n\n  char *w = xy_2strcat (w1, w2);\n\n  char *bashrc = xy_bashrc;\n  if (xy_file_exist (bashrc))\n    {\n      chsrc_backup (bashrc);\n      chsrc_append_to_file (w, bashrc);\n    }\n\n  char *zshrc = xy_zshrc;\n  if (xy_file_exist (zshrc))\n    {\n      chsrc_backup (zshrc);\n      chsrc_append_to_file (w, zshrc);\n    }\n\n  char *fishrc = xy_fishrc;\n  if (xy_file_exist (fishrc))\n    {\n      char *w1 = xy_strcat (3, \"set -x RUSTUP_DIST_SERVER \", source.url, \"\\n\");\n      char *w2 = xy_strcat (3, \"set -x RUSTUP_UPDATE_ROOT \", source.url, \"/rustup\\n\");\n\n      char *w = xy_2strcat (w1, w2);\n\n      chsrc_backup (fishrc);\n      chsrc_append_to_file (w, fishrc);\n    }\n#endif\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n  chsrc_alert2 (\"请重启终端使rustup环境变量生效\");\n}\n\n\n\nvoid\npl_rust_rustup_resetsrc (char *option)\n{\n  pl_rust_rustup_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/lang/rawstr4c.h",
    "content": "#pragma once\n\n/**\n * Generated by rawstr4c v1.0.0-2025/08/09\n */\n\nchar RAWSTR_pl_js_bun_config[] = \"\\133\\151\\156\\163\\164\\141\\154\\154\\135\\012\\162\\145\\147\\151\\163\\164\\162\\171\\040\\075\\040\\042\\100\\165\\162\\154\\100\\042\";\n\nchar RAWSTR_pl_java_maven_config[] = \"\\074\\155\\151\\162\\162\\157\\162\\076\\012\\040\\040\\040\\040\\074\\151\\144\\076\\100\\061\\100\\074\\057\\151\\144\\076\\012\\040\\040\\040\\040\\074\\155\\151\\162\\162\\157\\162\\117\\146\\076\\052\\074\\057\\155\\151\\162\\162\\157\\162\\117\\146\\076\\012\\040\\040\\040\\040\\074\\156\\141\\155\\145\\076\\100\\156\\141\\155\\145\\100\\074\\057\\156\\141\\155\\145\\076\\012\\040\\040\\040\\040\\074\\165\\162\\154\\076\\100\\165\\162\\154\\100\\074\\057\\165\\162\\154\\076\\012\\074\\057\\155\\151\\162\\162\\157\\162\\076\";\n\nchar RAWSTR_pl_java_build_gradle[] = \"\\141\\154\\154\\160\\162\\157\\152\\145\\143\\164\\163\\040\\173\\012\\040\\040\\040\\040\\162\\145\\160\\157\\163\\151\\164\\157\\162\\151\\145\\163\\040\\173\\012\\040\\040\\040\\040\\040\\040\\040\\040\\155\\141\\166\\145\\156\\040\\173\\040\\165\\162\\154\\040\\047\\100\\165\\162\\154\\100\\047\\040\\175\\012\\040\\040\\040\\040\\040\\040\\040\\040\\155\\141\\166\\145\\156\\114\\157\\143\\141\\154\\050\\051\\012\\040\\040\\040\\040\\040\\040\\040\\040\\155\\141\\166\\145\\156\\103\\145\\156\\164\\162\\141\\154\\050\\051\\012\\040\\040\\040\\040\\175\\012\\175\";\n\nchar RAWSTR_pl_rust_cargo_config[] = \"\\133\\163\\157\\165\\162\\143\\145\\056\\143\\162\\141\\164\\145\\163\\055\\151\\157\\135\\012\\162\\145\\160\\154\\141\\143\\145\\055\\167\\151\\164\\150\\040\\075\\040\\042\\155\\151\\162\\162\\157\\162\\042\\012\\012\\133\\163\\157\\165\\162\\143\\145\\056\\155\\151\\162\\162\\157\\162\\135\\012\\162\\145\\147\\151\\163\\164\\162\\171\\040\\075\\040\\042\\163\\160\\141\\162\\163\\145\\053\\100\\165\\162\\154\\100\\042\\012\";\n\nchar RAWSTR_pl_haskell_cabal_config[] = \"\\162\\145\\160\\157\\163\\151\\164\\157\\162\\171\\040\\155\\151\\162\\162\\157\\162\\012\\040\\040\\165\\162\\154\\072\\040\\100\\165\\162\\154\\100\\012\\040\\040\\163\\145\\143\\165\\162\\145\\072\\040\\124\\162\\165\\145\";\n\nchar RAWSTR_pl_haskell_stackage_yaml[] = \"\\160\\141\\143\\153\\141\\147\\145\\055\\151\\156\\144\\145\\170\\072\\012\\040\\040\\144\\157\\167\\156\\154\\157\\141\\144\\055\\160\\162\\145\\146\\151\\170\\072\\040\\100\\165\\162\\154\\100\\012\\040\\040\\150\\141\\143\\153\\141\\147\\145\\055\\163\\145\\143\\165\\162\\151\\164\\171\\072\\012\\040\\040\\040\\040\\153\\145\\171\\151\\144\\163\\072\\012\\040\\040\\040\\040\\040\\040\\055\\040\\060\\141\\065\\143\\067\\145\\141\\064\\067\\143\\144\\061\\142\\061\\065\\146\\060\\061\\146\\065\\146\\065\\061\\141\\063\\063\\141\\144\\144\\141\\067\\145\\066\\065\\065\\142\\143\\060\\146\\060\\142\\060\\066\\061\\065\\142\\141\\141\\070\\145\\062\\067\\061\\146\\064\\143\\063\\063\\065\\061\\145\\062\\061\\144\\012\\040\\040\\040\\040\\040\\040\\055\\040\\061\\145\\141\\071\\142\\141\\063\\062\\143\\065\\062\\066\\144\\061\\143\\143\\071\\061\\141\\142\\065\\145\\065\\142\\144\\063\\066\\064\\145\\143\\065\\145\\071\\145\\070\\143\\142\\066\\067\\061\\067\\071\\141\\064\\067\\061\\070\\067\\062\\146\\066\\145\\062\\066\\146\\060\\141\\145\\067\\067\\063\\144\\064\\062\\012\\040\\040\\040\\040\\040\\040\\055\\040\\062\\070\\060\\142\\061\\060\\061\\065\\063\\141\\065\\062\\062\\066\\070\\061\\061\\066\\063\\066\\065\\070\\143\\142\\064\\071\\146\\066\\063\\062\\143\\144\\145\\063\\146\\063\\070\\144\\067\\066\\070\\142\\067\\063\\066\\144\\144\\142\\143\\071\\060\\061\\144\\071\\071\\141\\061\\141\\067\\067\\062\\070\\063\\063\\012\\040\\040\\040\\040\\040\\040\\055\\040\\062\\141\\071\\066\\142\\061\\070\\070\\071\\144\\143\\062\\062\\061\\143\\061\\067\\062\\071\\066\\146\\143\\143\\062\\142\\142\\063\\064\\142\\071\\060\\070\\143\\141\\071\\067\\063\\064\\063\\067\\066\\146\\060\\146\\063\\066\\061\\066\\066\\060\\062\\060\\060\\071\\063\\065\\071\\061\\066\\145\\146\\062\\060\\061\\012\\040\\040\\040\\040\\040\\040\\055\\040\\062\\143\\066\\143\\063\\066\\062\\067\\142\\144\\066\\143\\071\\070\\062\\071\\071\\060\\062\\063\\071\\064\\070\\067\\146\\061\\141\\142\\144\\060\\062\\145\\060\\070\\141\\060\\062\\145\\066\\143\\146\\061\\066\\145\\144\\142\\061\\060\\065\\141\\070\\060\\061\\062\\144\\064\\064\\064\\144\\070\\067\\060\\143\\063\\012\\040\\040\\040\\040\\040\\040\\055\\040\\065\\061\\146\\060\\061\\066\\061\\142\\071\\060\\066\\060\\061\\061\\142\\065\\062\\143\\066\\066\\061\\063\\063\\067\\066\\142\\061\\141\\145\\071\\063\\067\\066\\067\\060\\144\\141\\066\\071\\063\\062\\062\\061\\061\\063\\141\\062\\064\\066\\141\\060\\071\\146\\070\\060\\067\\143\\066\\062\\146\\066\\071\\062\\061\\012\\040\\040\\040\\040\\040\\040\\055\\040\\067\\067\\062\\145\\071\\146\\064\\143\\067\\144\\142\\063\\063\\144\\062\\065\\061\\144\\065\\143\\066\\145\\063\\065\\067\\061\\071\\071\\143\\070\\061\\071\\145\\065\\066\\071\\144\\061\\063\\060\\070\\065\\067\\144\\143\\062\\062\\065\\065\\064\\071\\142\\064\\060\\070\\064\\065\\146\\146\\060\\070\\071\\060\\144\\012\\040\\040\\040\\040\\040\\040\\055\\040\\141\\141\\063\\061\\065\\062\\070\\066\\145\\066\\141\\144\\062\\070\\061\\141\\144\\066\\061\\061\\070\\062\\062\\063\\065\\065\\063\\063\\143\\064\\061\\145\\070\\060\\066\\145\\065\\141\\067\\070\\067\\145\\060\\142\\066\\144\\061\\145\\067\\145\\145\\146\\063\\146\\060\\071\\144\\061\\063\\067\\144\\062\\145\\071\\012\\040\\040\\040\\040\\040\\040\\055\\040\\146\\145\\063\\063\\061\\065\\060\\062\\066\\060\\066\\070\\060\\062\\146\\145\\141\\143\\061\\065\\145\\065\\061\\064\\144\\071\\142\\071\\145\\141\\070\\063\\146\\145\\145\\070\\142\\066\\146\\146\\145\\146\\067\\061\\063\\063\\065\\064\\067\\071\\141\\062\\145\\066\\070\\144\\070\\064\\141\\144\\143\\066\\142\\060\\012\\040\\040\\040\\040\\153\\145\\171\\055\\164\\150\\162\\145\\163\\150\\157\\154\\144\\072\\040\\063\\040\\043\\040\\156\\165\\155\\142\\145\\162\\040\\157\\146\\040\\153\\145\\171\\163\\040\\162\\145\\161\\165\\151\\162\\145\\144\\012\\040\\040\\040\\040\\043\\040\\151\\147\\156\\157\\162\\145\\040\\145\\170\\160\\151\\162\\141\\164\\151\\157\\156\\040\\144\\141\\164\\145\\054\\040\\163\\145\\145\\040\\150\\164\\164\\160\\163\\072\\057\\057\\147\\151\\164\\150\\165\\142\\056\\143\\157\\155\\057\\143\\157\\155\\155\\145\\162\\143\\151\\141\\154\\150\\141\\163\\153\\145\\154\\154\\057\\163\\164\\141\\143\\153\\057\\160\\165\\154\\154\\057\\064\\066\\061\\064\\012\\040\\040\\040\\040\\151\\147\\156\\157\\162\\145\\055\\145\\170\\160\\151\\162\\171\\072\\040\\156\\157\";\n\nchar RAWSTR_pl_clojure_project_clj[] = \"\\050\\144\\145\\146\\160\\162\\157\\152\\145\\143\\164\\040\\155\\171\\141\\160\\160\\040\\042\\061\\056\\060\\056\\060\\042\\012\\040\\040\\040\\072\\144\\145\\163\\143\\162\\151\\160\\164\\151\\157\\156\\040\\042\\115\\171\\040\\101\\160\\160\\154\\151\\143\\141\\164\\151\\157\\156\\042\\012\\040\\040\\040\\072\\144\\145\\160\\145\\156\\144\\145\\156\\143\\151\\145\\163\\040\\133\\133\\154\\151\\142\\061\\040\\042\\061\\056\\060\\056\\060\\042\\135\\012\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\133\\154\\151\\142\\062\\040\\042\\062\\056\\060\\056\\060\\042\\135\\012\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\133\\154\\151\\142\\063\\040\\042\\063\\056\\060\\056\\060\\042\\135\\135\\012\\040\\040\\040\\072\\155\\151\\162\\162\\157\\162\\163\\040\\173\\042\\143\\154\\157\\152\\141\\162\\163\\042\\040\\173\\072\\156\\141\\155\\145\\040\\042\\155\\151\\162\\162\\157\\162\\042\\012\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\040\\072\\165\\162\\154\\040\\042\\100\\165\\162\\154\\100\\042\\175\\175\\012\\040\\040\\040\\072\\155\\141\\151\\156\\040\\154\\145\\151\\156\\151\\156\\147\\145\\156\\056\\167\\145\\142\\051\";\n\nchar RAWSTR_pl_clojure_projfiles_clj[] = \"\\072\\165\\163\\145\\162\\040\\173\\072\\162\\145\\160\\157\\163\\151\\164\\157\\162\\151\\145\\163\\040\\133\\133\\042\\143\\154\\157\\152\\141\\162\\163\\042\\040\\173\\072\\165\\162\\154\\040\\042\\100\\165\\162\\154\\100\\042\\175\\135\\135\\012\\040\\040\\040\\040\\040\\040\\040\\073\\073\\040\\157\\164\\150\\145\\162\\040\\072\\165\\163\\145\\162\\040\\160\\162\\157\\146\\151\\154\\145\\040\\163\\145\\164\\164\\151\\156\\147\\163\\012\\040\\040\\040\\040\\040\\040\\175\";\n\n"
  },
  {
    "path": "src/recipe/lang/rawstr4c.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------------------------------------------------------------\n ! Config Type   : rawstr4c (Markdown)\n ! Config Authors: Aoran Zeng <ccmywish@qq.com>\n ! Contributors  : Happy Game <happygame1024@gmail.com>\n ! Created On    : <2025-07-14>\n ! Last Modified : <2025-09-13>\n ! ---------------------------------------------------------- -->\n\n# rawstr4c input for PL\n\n- prefix = `RAWSTR_pl`\n- output = `:global-variable-only-header`\n- translate = `:oct`\n- no-postfix = `true`\n\n<br>\n\n\n\n## Node.js\n\n- namespace = `nodejs`\n\n### Bun\n\n- name = `bun_config`\n\n```toml\n[install]\nregistry = \"@url@\"\n```\n\n<br>\n\n\n\n## Java\n\n- namespace = `java`\n\n### maven config\n\n```xml\n<mirror>\n    <id>@1@</id>\n    <mirrorOf>*</mirrorOf>\n    <name>@name@</name>\n    <url>@url@</url>\n</mirror>\n```\n\n\n### build.gradle\n\n```groovy\nallprojects {\n    repositories {\n        maven { url '@url@' }\n        mavenLocal()\n        mavenCentral()\n    }\n}\n```\n\n<br>\n\n\n\n## Rust\n\n- namespace = `rust`\n- name = `cargo_config`\n\n```toml\n[source.crates-io]\nreplace-with = \"mirror\"\n\n[source.mirror]\nregistry = \"sparse+@url@\"\n\n```\n\n<br>\n\n\n\n## Haskell\n\n- namespace = `haskell`\n\n### cabal config\n\n```\nrepository mirror\n  url: @url@\n  secure: True\n```\n\n\n### stackage\n\n- name = `stackage`\n- no-postfix = `false`\n- postfix = `yaml`\n\n```yaml\npackage-index:\n  download-prefix: @url@\n  hackage-security:\n    keyids:\n      - 0a5c7ea47cd1b15f01f5f51a33adda7e655bc0f0b0615baa8e271f4c3351e21d\n      - 1ea9ba32c526d1cc91ab5e5bd364ec5e9e8cb67179a471872f6e26f0ae773d42\n      - 280b10153a522681163658cb49f632cde3f38d768b736ddbc901d99a1a772833\n      - 2a96b1889dc221c17296fcc2bb34b908ca9734376f0f361660200935916ef201\n      - 2c6c3627bd6c982990239487f1abd02e08a02e6cf16edb105a8012d444d870c3\n      - 51f0161b906011b52c6613376b1ae937670da69322113a246a09f807c62f6921\n      - 772e9f4c7db33d251d5c6e357199c819e569d130857dc225549b40845ff0890d\n      - aa315286e6ad281ad61182235533c41e806e5a787e0b6d1e7eef3f09d137d2e9\n      - fe331502606802feac15e514d9b9ea83fee8b6ffef71335479a2e68d84adc6b0\n    key-threshold: 3 # number of keys required\n    # ignore expiration date, see https://github.com/commercialhaskell/stack/pull/4614\n    ignore-expiry: no\n```\n\n<br>\n\n\n\n## Clojar\n\n- namespace = `clojure`\n\n### project.clj\n\n```clojure\n(defproject myapp \"1.0.0\"\n   :description \"My Application\"\n   :dependencies [[lib1 \"1.0.0\"]\n                  [lib2 \"2.0.0\"]\n                  [lib3 \"3.0.0\"]]\n   :mirrors {\"clojars\" {:name \"mirror\"\n                        :url \"@url@\"}}\n   :main leiningen.web)\n```\n\n\n### projfiles.clj\n\n```clojure\n:user {:repositories [[\"clojars\" {:url \"@url@\"}]]\n       ;; other :user profile settings\n      }\n```\n"
  },
  {
    "path": "src/recipe/menu.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Authors   : 曾奥然 <ccmywish@qq.com>\n * Contributors   : Mikachu2333 <mikachu.23333@zohomail.com>\n *                | BingChunMoLi <bingchunmoli@bingchunmoli.com>\n *                |\n * Created On     : <2023-09-01>\n * Major Revision :      5\n * Last Modified  : <2025-08-22>\n * ------------------------------------------------------------*/\n\n#include \"lang/rawstr4c.h\"\n\n#include \"lang/Ruby/Ruby.c\"\n#include \"lang/Python/common.h\"\n #include \"lang/Python/pip.c\"\n  #include \"lang/Python/Poetry.c\"\n  #include \"lang/Python/PDM.c\"\n  #include \"lang/Python/Rye.c\"\n  #include \"lang/Python/uv.c\"\n#include \"lang/Python/Python.c\"\n\n#include \"lang/JavaScript/common.h\"\n  #include \"lang/JavaScript/npm.c\"\n  #include \"lang/JavaScript/pnpm.c\"\n  #include \"lang/JavaScript/Yarn.c\"\n#include \"lang/JavaScript/JavaScript.c\"\n#include \"lang/JavaScript/Bun.c\"\n#include \"lang/JavaScript/nvm.c\"\n\n#include \"lang/Perl.c\"\n#include \"lang/PHP.c\"\n#include \"lang/Lua.c\"\n#include \"lang/Go.c\"\n#include \"lang/Java.c\"\n\n#include \"lang/Rust/common.h\"\n  #include \"lang/Rust/rustup.c\"\n  #include \"lang/Rust/Cargo.c\"\n\n#include \"lang/Dart/common.h\"\n#include \"lang/Dart/Pub.c\"\n#include \"lang/Dart/Flutter.c\"\n\n#include \"lang/Haskell.c\"\n#include \"lang/OCaml.c\"\n#include \"lang/R.c\"\n#include \"lang/Julia.c\"\n#include \"lang/NuGet.c\"\n#include \"lang/Clojure.c\"\n\n\n#include \"os/rawstr4c.h\"\n#include \"os/APT/common.h\"\n// Debian-based\n#include \"os/APT/Debian.c\"\n#include \"os/APT/Ubuntu.c\"\n#include \"os/APT/Kali-Linux.c\"\n#include \"os/APT/Raspberry-Pi-OS.c\"\n// Ubuntu-based\n#include \"os/APT/Linux-Mint.c\"\n#include \"os/APT/Trisquel.c\"\n#include \"os/APT/Linux-Lite.c\"\n// Debian-based and Ubuntu-based\n#include \"os/APT/Armbian.c\"\n// Independent\n#include \"os/APT/ROS.c\"\n#include \"os/APT/Termux.c\"\n#include \"os/APT/openKylin.c\"\n#include \"os/APT/deepin.c\"\n\n#include \"os/YUM/common.h\"\n#include \"os/YUM/Fedora-Linux.c\"\n#include \"os/YUM/AlmaLinux.c\"\n#include \"os/YUM/Rocky-Linux.c\"\n#include \"os/YUM/openEuler.c\"\n#include \"os/YUM/Anolis-OS.c\"\n\n#include \"os/pacman/Arch-Linux.c\"\n#include \"os/pacman/Manjaro-Linux.c\"\n#include \"os/pacman/MSYS2.c\"\n\n#include \"os/openSUSE.c\"\n#include \"os/Alpine-Linux.c\"\n#include \"os/Gentoo-Linux.c\"\n#include \"os/Void-Linux.c\"\n#include \"os/Solus.c\"\n#include \"os/OpenWrt.c\"\n\n#include \"os/BSD/FreeBSD.c\"\n#include \"os/BSD/NetBSD.c\"\n#include \"os/BSD/OpenBSD.c\"\n\n\n#include \"ware/TeX-Live.c\"\n#include \"ware/Emacs.c\"\n#include \"ware/WinGet.c\"\n#include \"ware/Homebrew/Homebrew.c\"\n#include \"ware/CocoaPods.c\"\n#include \"ware/Nix.c\"\n#include \"ware/Guix.c\"\n#include \"ware/Flatpak.c\"\n#include \"ware/Docker/Docker.c\"\n#include \"ware/Anaconda/Anaconda.c\"\n\n\nvoid\nchsrc_init_menu ()\n{\n#define add(t) xy_seq_push(ProgStore.pl, &pl_##t##_target); (&pl_##t##_target)->preludefn = pl_##t##_prelude\n  add (ruby);\n  add (python_group);\n  add (python_pip);\n  add (python_poetry);\n  add (python_pdm);\n  add (python_rye);\n  add (python_uv);\n  add (js_group);\n  add (js_bun);\n  add (js_npm);\n  add (js_yarn);\n  add (js_pnpm);\n  add (js_nvm);\n  add (perl);\n  add (php);\n  add (lua);\n  add (go);\n  add (rust_cargo);\n  add (rust_rustup);\n  add (java);\n  add (clojure);\n  add (dart);\n  add (dart_flutter);\n  add (nuget);\n  add (haskell);\n  add (ocaml);\n  add (r);\n  add (julia);\n#undef add\n\n#define add(t) xy_seq_push(ProgStore.os, &os_##t##_target); (&os_##t##_target)->preludefn = os_##t##_prelude\n  add (ubuntu);\n  add (linuxmint);\n  add (debian);\n  add (fedora);\n  add (opensuse);\n  add (kali);\n  add (msys2);\n  add (arch);\n  add (archlinuxcn);\n  add (manjaro);\n  add (gentoo);\n  add (rockylinux);\n  add (almalinux);\n  add (alpine);\n  add (voidlinux);\n  add (solus);\n  add (trisquel);\n  add (linuxlite);\n  add (ros);\n  add (raspberrypi);\n  add (armbian);\n  add (openwrt);\n  add (termux);\n  add (openkylin);\n  add (openeuler);\n  add (anolis);\n  add (deepin);\n  add (freebsd);\n  add (netbsd);\n  add (openbsd);\n#undef add\n\n#define add(t) xy_seq_push(ProgStore.wr, &wr_##t##_target); (&wr_##t##_target)->preludefn = wr_##t##_prelude\n  add (winget);\n  add (homebrew);\n  add (cocoapods);\n  add (docker);\n  add (flatpak);\n  add (nix);\n  add (guix);\n  add (emacs);\n  add (tex);\n  add (anaconda);\n#undef add\n\n  // Internal Target 不会由用户使用，需要特殊对待\n  pl_js_nodejs_binary_target.preludefn = pl_js_nodejs_binary_prelude;\n}\n\n\n\n/**\n * @sync https://github.com/RubyMetric/chsrc/wiki\n */\nstatic MirrorSite_t*\nchsrc_available_mirrors[] = {\n\n  /* ------------------------ 教育网(通用镜像站) ------------------------ */\n  &MirrorZ, &Tuna, &Sjtug_Zhiyuan, &Sjtug_Siyuan, &Bfsu, &Ustc, &Zju, &Jlu, &Lzuoss, &Pku, &Bjtu, &Sustech, &Nju, &Xjtu,\n\n  &Hust,   &Iscas, &Hit, &Scau,\n  &NJTech, &Nyist, &Sdu, &Qlu,\n  &Cqupt,  &Cqu,   &Neosoft,\n\n\n  /* ------------------------ 商业公司(通用镜像站) ------------------------ */\n  &Ali,     // &Ali_ECS_VPC, &Ali_ECS_classic,\n  &Tencent, // &Tencent_Intra,\n  &Huawei, &HuaweiCDN,\n  &Volcengine,\n  &Netease,\n  &Sohu,\n\n  &Api7, &Fit2Cloud, &DaoCloud,\n\n\n  /* ------------------------ 专用镜像站 ------------------------ */\n  &RubyChina, &EmacsChina, &NpmMirror, &GoProxyIO, &GoProxyCN, &RsProxyCN, &FlutterCN,\n  /* 暂不支持 &NugetOrg */\n\n\n  /* ------------------------ chsrc 内部实现 ------------------------ */\n  /* 不要列出 &UpstreamProvider 和 &UserDefinedProvider */\n};\n"
  },
  {
    "path": "src/recipe/os/APT/Armbian.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_armbian, \"armbian\");\n\nvoid\nos_armbian_prelude ()\n{\n  chef_prep_this (os_armbian, gsr);\n\n  chef_set_recipe_created_on   (this, \"2024-06-14\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2024-11-21\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@livelycode36\");\n  chef_set_sauciers (this, 2, \"@ccmywish\", \"@Yangmoooo\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"http://apt.armbian.com\", DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/armbian\",        DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/armbian\", DelegateToMirror},\n  {&Sjtug_Zhiyuan,    \"https://mirror.sjtu.edu.cn/armbian\",            DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/armbian\",           DelegateToMirror},\n  {&Sustech,          \"https://mirrors.sustech.edu.cn/armbian\",        DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/armbian\",           DelegateToMirror},\n  {&Nju,              \"https://mirrors.nju.edu.cn/armbian\",             DelegateToMirror},\n  {&Ali,              \"https://mirrors.aliyun.com/armbian\",             DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_armbian_getsrc (char *option)\n{\n  if (chsrc_check_file (OS_Armbian_SourceList))\n    {\n      chsrc_view_file (OS_Armbian_SourceList);\n      return;\n    }\n\n  char *msg = ENGLISH ? \"Source list config file missing! Path: \" OS_Armbian_SourceList\n                      : \"缺少源配置文件！路径：\" OS_Armbian_SourceList;\n  chsrc_error2 (msg);\n}\n\n\n/**\n * @consult https://mirrors.tuna.tsinghua.edu.cn/help/armbian\n */\nvoid\nos_armbian_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_armbian);\n\n  chsrc_backup (OS_Armbian_SourceList);\n\n  char *cmd = xy_strcat (3, \"sed -E -i 's@https?[^ ]*armbian/?[^ ]*@\", source.url,\n                             \"@g' \" OS_Armbian_SourceList);\n\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_armbian_resetsrc (char *option)\n{\n  os_armbian_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/APT/Debian.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_debian, \"debian\");\n\nvoid\nos_debian_prelude ()\n{\n  chef_prep_this (os_debian, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-02\");\n  chef_set_recipe_last_updated (this, \"2025-11-09\");\n  chef_set_sources_last_updated (this, \"2025-07-11\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 2, \"@ccmywish\", \"@G_I_Y\");\n  chef_set_sauciers (this, 1, \"@Yangmoooo\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"http://deb.debian.org/debian\",          FeedByPrelude},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/debian\",  FeedByPrelude},\n  {&Ali,              \"https://mirrors.aliyun.com/debian\", FeedByPrelude},\n  {&Volcengine,       \"https://mirrors.volces.com/debian\", FeedByPrelude},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/debian\", FeedByPrelude},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/debian\", FeedByPrelude},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/debian\", FeedByPrelude},\n  {&Tencent,          \"https://mirrors.tencent.com/debian\", FeedByPrelude}\n\n  // {&Tencent_Intra, \"https://mirrors.tencentyun.com/debian\", FeedByPrelude},\n\n  /* 不启用原因：过慢 */\n  // {&Netease,     \"https://mirrors.163.com/debian\", FeedByPrelude},\n\n  /* 不启用原因：过慢 */\n  // {&Sohu,        \"https://mirrors.sohu.com/debian\", FeedByPrelude}\n  def_sources_end()\n\n  chef_set_rest_smURL_with_postfix (this, \"/dists/bookworm/main/Contents-all.gz\");\n}\n\n\nvoid\nos_debian_getsrc (char *option)\n{\n  if (chsrc_check_file (OS_Debian_SourceList_DEB822))\n    {\n      chsrc_view_file (OS_Debian_SourceList_DEB822);\n      return;\n    }\n\n  if (chsrc_check_file (OS_Debian_old_SourceList))\n    {\n      chsrc_view_file (OS_Debian_old_SourceList);\n      return;\n    }\n\n  char *msg = ENGLISH ? \"Source list file missing! However, you can still run `chsrc set debian` to add and use new sources\"\n                      : \"缺少源配置文件！但仍可直接通过 chsrc set debian 来添加使用新的源\";\n  chsrc_error2 (msg);\n  return;\n}\n\n\nstatic bool\nos_debian_does_old_sourcelist_use_cdrom (void)\n{\n  /* 我们只检查旧版sourcelist，因为 common.h 中的填充只支持旧版 */\n  char *cmd = xy_2strcat (\"grep -q '^deb cdrom:' \", OS_Debian_old_SourceList);\n  int ret = xy_run_get_status (cmd);\n  bool use_cdrom = ret == 0;\n\n  return use_cdrom;\n}\n\n\nvoid\nos_debian_setsrc_for_deb822 (char *option)\n{\n  chsrc_use_this_source (os_debian);\n\n  chsrc_backup (OS_Debian_SourceList_DEB822);\n\n  char *cmd = xy_strcat (3, \"sed -E -i 's@https?://.*/debian/?@\", source.url, \"@g' \" OS_Debian_SourceList_DEB822);\n  chsrc_run (cmd, RunOpt_Default);\n\n  /* debian-security 源和其他源不一样 */\n  cmd = xy_strcat (3, \"sed -E -i 's@https?://.*/debian-security/?@\", source.url, \"-security@g' \" OS_Debian_SourceList_DEB822);\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\n/**\n * 处理旧版(非DEB822) sourcelist 的换源\n *\n * Debian 10 Buster 以上版本默认支持 HTTPS 源。如果遇到无法拉取 HTTPS 源的情况，请先使用 HTTP 源并安装\n * apt install apt-transport-https ca-certificates\n */\nvoid\nos_debian_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  if (chsrc_check_file (OS_Debian_SourceList_DEB822))\n    {\n      chsrc_note2 (\"将基于新格式(DEB822)换源\");\n      os_debian_setsrc_for_deb822 (option);\n      return;\n    }\n\n  chsrc_alert2 (\"将基于旧格式(非DEB822)换源\");\n\n  /* Docker环境下，Debian镜像可能不存在该文件 */\n  bool sourcelist_exist = ensure_debian_or_ubuntu_old_sourcelist (OS_Is_Debian_Literally);\n\n  /**\n   * 处理带有CDROM源的sourcelist\n   *\n   * https://github.com/RubyMetric/chsrc/issues/185#issuecomment-2746072917\n   */\n  if (sourcelist_exist)\n    {\n      bool use_cdrom = os_debian_does_old_sourcelist_use_cdrom();\n      if (use_cdrom)\n        {\n          chsrc_backup (OS_Debian_old_SourceList);\n          int rm_status = xy_run_get_status (\"rm \" OS_Debian_old_SourceList);\n          if (rm_status != 0) { /* Placate -Wunused-result */ }\n\n          chsrc_warn2 (\"旧版源配置文件中使用了 CDROM 源，已删除(但备份)该配置文件，重新配置\");\n          /* 现在的情况是：系统中已经没有配置文件了 */\n          sourcelist_exist = ensure_debian_or_ubuntu_old_sourcelist (OS_Is_Debian_Literally);\n        }\n    }\n\n  chsrc_use_this_source (os_debian);\n\n  chsrc_alert2 (\"如果遇到无法拉取 HTTPS 源的情况，请手动运行:\");\n  say (\"apt install apt-transport-https ca-certificates\");\n\n  /* 不存在的时候，用的是我们生成的用来填充占位的无效文件，不要备份 */\n  if (sourcelist_exist)\n    {\n      chsrc_backup (OS_Debian_old_SourceList);\n    }\n\n  char *cmd = xy_strcat (3, \"sed -E -i \\'s@https?://.*/debian/?@\", source.url, \"@g\\' \" OS_Debian_old_SourceList);\n\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_debian_resetsrc (char* option)\n{\n  os_debian_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/APT/Kali-Linux.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_kali, \"kali\");\n\nvoid\nos_kali_prelude ()\n{\n  chef_prep_this (os_kali, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-29\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-06-20\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@G_I_Y\");\n  chef_set_sauciers (this, 2, \"@Yangmoooo\", \"@happy-game\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"http://http.kali.org/kali\",          DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/kali\", DelegateToMirror},\n  {&Ali,              \"https://mirrors.aliyun.com/kali\",    DelegateToMirror},\n  {&Volcengine,       \"https://mirrors.volces.com/kali\",    DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/kali\",   DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/kali\",   DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/kali\", DelegateToMirror}\n  /* 不启用原因: 未与上游同步 */\n  // {&Huawei,     \"https://mirrors.huaweicloud.com/kali\",   DelegateToMirror},\n  def_sources_end()\n}\n\nvoid\nos_kali_getsrc (char *option)\n{\n  chsrc_view_file (OS_Apt_SourceList);\n}\n\nvoid\nos_kali_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_kali);\n\n  chsrc_backup (OS_Apt_SourceList);\n\n  char *cmd = xy_strcat (3, \"sed -E -i \\'s@https?://.*/kali/?@\",\n                              source.url,\n                             \"@g\\' \" OS_Apt_SourceList);\n\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_kali_resetsrc (char *option)\n{\n  os_kali_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/APT/Linux-Lite.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_linuxlite, \"linuxlite\");\n\nvoid\nos_linuxlite_prelude ()\n{\n  chef_prep_this (os_linuxlite, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-29\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2024-11-21\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@Yangmoooo\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"http://repo.linuxliteos.com/linuxlite/\",    DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/linuxliteos/\",    DelegateToMirror},\n  {&Sjtug_Zhiyuan,    \"https://mirrors.sjtug.sjtu.edu.cn/linuxliteos/\", DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn/linuxliteos/\",         DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_linuxlite_getsrc (char *option)\n{\n  chsrc_view_file (OS_Apt_SourceList);\n}\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/linuxliteos/\n */\nvoid\nos_linuxlite_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_linuxlite);\n\n  chsrc_backup (OS_Apt_SourceList);\n\n  char *cmd = xy_strcat (3, \"sed -E -i 's@https?://.*/.*/?@\", source.url, \"@g' \" OS_Apt_SourceList);\n\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_linuxlite_resetsrc (char *option)\n{\n  os_linuxlite_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/APT/Linux-Mint.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_linuxmint, \"linuxmint\");\n\nvoid\nos_linuxmint_prelude ()\n{\n  chef_prep_this (os_linuxmint, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-29\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2024-11-21\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@happy-game\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n\n  /* @note 实际上镜像站里的内容和Ubuntu的不太一样 */\n  def_sources_begin()\n  {&UpstreamProvider, \"http://packages.linuxmint.com\",                   DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/linuxmint/\",        DelegateToMirror},\n  {&Ali,              \"http://mirrors.aliyun.com/linuxmint-packages/\",   DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/linuxmint/\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/linuxmint/\",          DelegateToMirror},\n  {&Sjtug_Zhiyuan,    \"https://mirror.sjtu.edu.cn/linuxmint/\",            DelegateToMirror},\n  {&Jlu,              \"https://mirrors.jlu.edu.cn/linuxmint/\",            DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/linuxmint/\",           DelegateToMirror},\n  {&Bjtu,             \"https://mirror.bjtu.edu.cn/linuxmint/\",             DelegateToMirror},\n  {&Zju,              \"https://mirrors.zju.edu.cn/linuxmint/\",             DelegateToMirror},\n  {&Sustech,          \"https://mirrors.sustech.edu.cn/linuxmint/\",         DelegateToMirror},\n  {&Iscas,            \"https://mirror.iscas.ac.cn/linuxmint/\",             DelegateToMirror},\n  {&Scau,             \"https://mirrors.scau.edu.cn/linuxmint/\",            DelegateToMirror}\n  /* 不启用原因：过慢 */\n  // {&Netease,     \"https://mirrors.163.com/linuxmint/packages/\",       DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_linuxmint_getsrc (char *option)\n{\n  chsrc_view_file (OS_LinuxMint_SourceList);\n}\n\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/linuxmint/\n */\nvoid\nos_linuxmint_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_linuxmint);\n\n  chsrc_backup (OS_LinuxMint_SourceList);\n\n  // deb xxx wilma main upstream import backport 为mint主要源, wilma为版本代号\n  // 暂不实现自动替换基于debian或ubuntu的基础源\n  char *version_codename = xy_run (\"sed -nr 's/^VERSION_CODENAME=([^\\\"]+)/\\1/p' \" ETC_OS_RELEASE, 0);\n  // sed -i '/<version_codename>/ s|http[^ ]*|<source.url>|g' OS_LinuxMint_SourceList\n  char* cmd = xy_strcat (5, \"sed -i '/\",\n                          version_codename, \"/ s|http[^ ]*|\",\n                          source.url, \"|g' \"  OS_LinuxMint_SourceList);\n\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n  chsrc_warn2 (\"完成后请不要再使用 mintsources（自带的图形化软件源设置工具）进行任何操作，因为在操作后，无论是否有按“确定”，mintsources 均会覆写我们刚才换源的内容\");\n  chsrc_warn2 (\"已自动更换mint主要源, 但mint也使用基于debian或ubuntu的基础源, 可参考对应的debian或ubuntu换源方法进行手动换源\");\n}\n"
  },
  {
    "path": "src/recipe/os/APT/ROS.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_ros, \"ros/ros2\");\n\nvoid\nos_ros_prelude ()\n{\n  chef_prep_this (os_ros, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-03\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2024-04-18\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@G_I_Y\");\n  chef_set_sauciers (this, 2, \"@ccmywish\", \"@zouri\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, \"该换源方案中，URL存在拼凑，因此不能手动使用某URL来换源\", \"In this switching method, URLs are constructed, so manual URL specification is not supported\");\n\n  def_sources_begin()\n  {&UpstreamProvider, \"http://packages.ros.org\",     DelegateToUpstream},\n  {&Ali,              \"https://mirrors.aliyun.com\",  DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn\", DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn\", DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn\", DelegateToMirror},\n  {&Tencent,          \"https://mirrors.tencent.com\", DelegateToMirror},\n  // {&Tencent_Intra, \"https://mirrors.tencentyun.com\", DelegateToMirror},\n  {&Huawei,           \"https://mirrors.huaweicloud.com\", DelegateToMirror}\n  /* 不启用原因：过慢 */\n  // {&Netease,       \"https://mirrors.163.com\", DelegateToMirror},\n  /* 不启用原因：过慢 */\n  // {&Sohu,          \"https://mirrors.sohu.com\", DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_ros_getsrc (char *option)\n{\n  chsrc_view_file (OS_ROS_SourceList);\n}\n\n\n/**\n * @consult https://mirrors.tuna.tsinghua.edu.cn/help/ros/\n */\nvoid\nos_ros_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_ros);\n\n  chsrc_backup (OS_ROS_SourceList);\n\n  char *cmd  = NULL;\n  cmd = xy_strcat(3, \"sed -E -i \\'s@https?://.*/ros/ubuntu/?@\", source.url, \"/ros/ubuntu@g\\' \" OS_ROS_SourceList);\n  chsrc_run(cmd, RunOpt_Default);\n\n  cmd = \"apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654\";\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/APT/Raspberry-Pi-OS.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * Raspberry Pi OS 树莓派操作系统，以前称为 Raspbian\n * ------------------------------------------------------------*/\n\ndef_target(os_raspberrypi, \"raspi/raspberrypi\");\n\nvoid\nos_raspberrypi_prelude ()\n{\n  chef_prep_this (os_raspberrypi, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-29\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2023-09-29\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@Yangmoooo\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  // https://archive.raspberrypi.org/ until Debian \"bullseye\" release\n  {&UpstreamProvider, \"https://archive.raspberrypi.com/\",              DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/raspberrypi/\",    DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/raspberrypi/\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/raspberrypi/\",      DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/raspberrypi/\",      DelegateToMirror},\n  {&Sjtug_Zhiyuan,    \"https://mirrors.sjtug.sjtu.edu.cn/raspberrypi/\", DelegateToMirror},\n  {&Sustech,          \"https://mirrors.sustech.edu.cn/raspberrypi/\",   DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_raspberrypi_getsrc (char *option)\n{\n  chsrc_view_file (OS_RaspberryPi_SourceList);\n}\n\n\nvoid\nos_raspberrypi_setsrc (char *option)\n{\n  chsrc_ensure_root(); // HELP: 不确定是否需要\n\n  chsrc_use_this_source (os_raspberrypi);\n\n  chsrc_backup (OS_RaspberryPi_SourceList);\n\n  char *cmd = xy_strcat (3, \"sed -E -i 's@https?://.*/.*/?@\", source.url,\n                            \"@g' \" OS_RaspberryPi_SourceList);\n\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_raspberrypi_resetsrc (char *option)\n{\n  os_raspberrypi_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/APT/Termux.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_termux, \"termux\");\n\nvoid\nos_termux_prelude ()\n{\n  chef_prep_this (os_termux, gsr);\n\n  chef_set_recipe_created_on   (this, \"2025-03-04\");\n  chef_set_recipe_last_updated (this, \"2026-01-21\");\n  chef_set_sources_last_updated (this, \"2025-03-04\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, \"该 recipe 存在对应的 bootstrapper\", \"This recipe has a corresponding bootstrapper\");\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://packages.termux.org/apt/termux-main/\", DelegateToUpstream},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/termux/\", DelegateToMirror},\n  {&Sjtug_Zhiyuan,    \"https://mirror.sjtu.edu.cn/termux/\",   DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/termux/\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/termux/\",  DelegateToMirror},\n  {&Pku,              \"https://mirrors.pku.edu.cn/termux/\",   DelegateToMirror},\n  {&Nyist,            \"https://mirror.nyist.edu.cn/termux/\",  DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn/termux/\",    DelegateToMirror},\n  {&Sustech,          \"https://mirrors.sustech.edu.cn/termux/\", DelegateToMirror},\n  {&Iscas,            \"https://mirror.iscas.ac.cn/termux/\",   DelegateToMirror},\n  {&Zju,              \"https://mirrors.zju.edu.cn/termux/\",   DelegateToMirror},\n  {&Sdu,              \"https://mirrors.sdu.edu.cn/termux/\",   DelegateToMirror},\n  {&Cqupt,            \"https://mirrors.cqupt.edu.cn/termux/\", DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_termux_getsrc (char *option)\n{\n  chsrc_view_file (OS_Termux_SourceList);\n}\n\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/termux/\n *\n * chsrc set termux\n */\nvoid\nos_termux_setsrc (char *option)\n{\n  // chsrc_ensure_root (); Termux下禁止使用root\n\n  chsrc_use_this_source (os_termux);\n\n  char *cmd = xy_strcat (3, \"sed -i 's@^\\\\(deb.*stable main\\\\)$@#\\\\1\\\\ndeb \",\n                              source.url, \"apt/termux-main stable main@' \" OS_Termux_SourceList);\n\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_run (\"apt-get update\",  RunOpt_Default);\n  chsrc_run (\"apt-get upgrade\", RunOpt_Default);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\nvoid\nos_termux_resetsrc (char *option)\n{\n  os_termux_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/APT/Trisquel.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * Trisquel基于Ubuntu开发，不含任何专有软件及专有固件，内核使用 Linux-libre\n * ------------------------------------------------------------*/\n\ndef_target(os_trisquel, \"trisquel\");\n\nvoid\nos_trisquel_prelude ()\n{\n  chef_prep_this (os_trisquel, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-29\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2024-11-21\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"http://archive.trisquel.info/trisquel/\", DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/trisquel/\", DelegateToMirror},\n  {&Ali,              \"https://mirrors.aliyun.com/trisquel/\",    DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn/trisquel/\",     DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/trisquel/\",   DelegateToMirror},\n  {&Iscas,            \"https://mirror.iscas.ac.cn/trisquel/\",    DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_trisquel_getsrc (char *option)\n{\n  chsrc_view_file (OS_Apt_SourceList);\n}\n\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/trisquel/\n */\nvoid\nos_trisquel_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_trisquel);\n\n  chsrc_backup (OS_Apt_SourceList);\n\n  char *cmd = xy_strcat (3, \"sed -E -i 's@https?://.*/trisquel/?@\", source.url, \"@g' /etc/apt/sources.list\");\n\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_trisquel_resetsrc (char *option)\n{\n  os_trisquel_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/APT/Ubuntu.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\n/* Zorin OS 完全使用 Ubuntu 的换源方法，二者兼容 */\ndef_target(os_ubuntu, \"ubuntu/zorinos\");\n\nvoid\nos_ubuntu_prelude ()\n{\n  chef_prep_this (os_ubuntu, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-08-30\");\n  chef_set_recipe_last_updated (this, \"2026-01-21\");\n  chef_set_sources_last_updated (this, \"2026-01-21\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 2, \"@ccmywish\", \"@G_I_Y\");\n  chef_set_sauciers (this, 2, \"@XUANJI233\", \"@usernameisnull\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"http://archive.ubuntu.com/ubuntu\",  FeedByPrelude}, /* 不支持https */\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/ubuntu\",FeedByPrelude},\n  {&Ali,              \"https://mirrors.aliyun.com/ubuntu\",FeedByPrelude},\n  {&Volcengine,       \"https://mirrors.volces.com/ubuntu\",FeedByPrelude},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/ubuntu\",FeedByPrelude},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/ubuntu\",FeedByPrelude},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/ubuntu\",FeedByPrelude},\n  {&Tencent,          \"https://mirrors.tencent.com/ubuntu\", FeedByPrelude},\n  // {&Tencent_Intra, \"https://mirrors.tencentyun.com/ubuntu\",FeedByPrelude},\n  {&Huawei,           \"https://mirrors.huaweicloud.com/ubuntu\",FeedByPrelude}\n\n  /* 不启用原因：过慢 */\n  // {&Netease,          \"https://mirrors.163.com/ubuntu\", FeedByPrelude},\n\n  /* 不启用原因：过慢 */\n  // {&Sohu,             \"https://mirrors.sohu.com/ubuntu\", FeedByPrelude}\n  def_sources_end()\n\n  char *arch = chsrc_get_cpuarch ();\n  // Ubuntu 非 x86_64 架构的默认源地址有所不同\n  if (strncmp (arch, \"x86_64\", 6)!=0)\n    {\n      chef_set_repoURL (this, &UpstreamProvider, \"http://ports.ubuntu.com/ubuntu\");\n    }\n\n  chef_set_rest_smURL_with_postfix (this, \"/dists/noble/Contents-amd64.gz\");\n}\n\n\nvoid\nos_ubuntu_getsrc (char *option)\n{\n  if (chsrc_check_file (OS_Ubuntu_SourceList_DEB822))\n    {\n      chsrc_view_file (OS_Ubuntu_SourceList_DEB822);\n      return;\n    }\n\n  if (chsrc_check_file (OS_Ubuntu_old_SourceList))\n    {\n      chsrc_view_file (OS_Ubuntu_old_SourceList);\n      return;\n    }\n\n  char *msg = ENGLISH ? \"Source list file missing! However, you can still run `chsrc set ubuntu` to add and use new sources\"\n                      : \"缺少源配置文件！但仍可直接通过 chsrc set ubuntu 来添加使用新的源\";\n  chsrc_error2 (msg);\n  return;\n}\n\n\n/**\n * 此函数基本和 os_ubuntu_setsrc() 一致\n */\nvoid\nos_ubuntu_setsrc_for_deb822 (char *option)\n{\n  chsrc_use_this_source (os_ubuntu);\n\n  chsrc_backup (OS_Ubuntu_SourceList_DEB822);\n\n  char *arch = chsrc_get_cpuarch ();\n  char *cmd  = NULL;\n  if (strncmp (arch, \"x86_64\", 6)==0)\n    {\n      cmd = xy_strcat (3, \"sed -E -i \\'s@https?://.*/ubuntu/?@\", source.url, \"@g\\' \" OS_Ubuntu_SourceList_DEB822);\n    }\n  else\n    {\n      cmd = xy_strcat (3, \"sed -E -i \\'s@https?://.*/ubuntu-ports/?@\", source.url, \"-ports@g\\' \" OS_Ubuntu_SourceList_DEB822);\n    }\n\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n/**\n * @note 不同架构下换源不一样\n */\nvoid\nos_ubuntu_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  if (chsrc_check_file (OS_Ubuntu_SourceList_DEB822))\n    {\n      char *msg = ENGLISH ? \"Will change source based on new format\"\n                          : \"将基于新格式(DEB822)换源\";\n      chsrc_note2 (msg);\n      os_ubuntu_setsrc_for_deb822 (option);\n      return;\n    }\n\n  chsrc_alert2 (\"将基于旧格式(非DEB822)换源\");\n\n  bool sourcelist_exist = ensure_debian_or_ubuntu_old_sourcelist (OS_Is_Ubuntu);\n\n  chsrc_use_this_source (os_ubuntu);\n\n  /* 不存在的时候，用的是我们生成的无效文件，不要备份 */\n  if (sourcelist_exist)\n    {\n      chsrc_backup (OS_Ubuntu_old_SourceList);\n    }\n\n  char *arch = chsrc_get_cpuarch();\n  char *cmd  = NULL;\n  if (0==strncmp (arch, \"x86_64\", 6))\n    {\n      cmd = xy_strcat (3, \"sed -E -i \\'s@https?://.*/ubuntu/?@\", source.url, \"@g\\' \" OS_Ubuntu_old_SourceList);\n    }\n  else\n    {\n      cmd = xy_strcat (3, \"sed -E -i \\'s@https?://.*/ubuntu-ports/?@\", source.url, \"-ports@g\\' \" OS_Ubuntu_old_SourceList);\n    }\n\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_ubuntu_resetsrc (char *option)\n{\n  os_ubuntu_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/APT/common.h",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Authors   : Aoran Zeng <ccmywish@qq.com>\n * Contributors   : happy game <happygame1024@gmail.com>\n *                |\n * Created On     : <2024-06-14>\n * Major Revision :      3\n * Last Modified  : <2025-07-14>\n * ------------------------------------------------------------*/\n\n#include \"rawstr4c.h\"\n\n#define OS_Apt_SourceList   \"/etc/apt/sources.list\"\n#define OS_Apt_SourceList_D \"/etc/apt/sources.list.d/\"\n\n/**\n * @note 从 Debian 12 (bookworm) 开始，Debain 的软件源配置文件变更为 DEB822 格式，\n *       路径为:  /etc/apt/sources.list.d/debian.sources\"\n *\n * @note 从 Ubuntu 24.04 开始，Ubuntu 的软件源配置文件变更为 DEB822 格式，\n *       路径为:  /etc/apt/sources.list.d/ubuntu.sources\n */\n#define OS_Debian_SourceList_DEB822 \"/etc/apt/sources.list.d/debian.sources\"\n#define OS_Ubuntu_SourceList_DEB822 \"/etc/apt/sources.list.d/ubuntu.sources\"\n\n#define OS_Debian_old_SourceList OS_Apt_SourceList\n#define OS_Ubuntu_old_SourceList OS_Apt_SourceList\n\n\n#define ETC_OS_RELEASE    \"/etc/os-release\"\n\n#define OS_Is_Debian_Literally  1\n#define OS_Is_Ubuntu            2\n\n// independent\n#define OS_ROS_SourceList         OS_Apt_SourceList_D \"ros-latest.list\"\n\n#define OS_Termux_SourceList      \"/data/data/com.termux/files/usr\" OS_Apt_SourceList\n\n\n// Ubuntu based\n#define OS_LinuxMint_SourceList   OS_Apt_SourceList_D \"official-package-repositories.list\"\n\n// Debian based\n#define OS_Armbian_SourceList     OS_Apt_SourceList_D \"armbian.list\"\n#define OS_RaspberryPi_SourceList OS_Apt_SourceList_D \"raspi.list\"\n\n\n/**\n * 当不存在该文件时，我们只能拼凑一个假的出来，但该函数目前只适用于 Ubuntu 和 Debian\n * 因为其它的 Debian 变体可能不使用 OS_Apt_SourceList，也可能并不适用 `VERSION_CODENAME`\n *\n * @return 文件是否存在\n */\nbool\nensure_debian_or_ubuntu_old_sourcelist (int debian_type)\n{\n  bool exist = chsrc_check_file (OS_Apt_SourceList);\n\n  if (exist)\n    {\n      return true;\n    }\n  else\n    {\n      char *msg = ENGLISH ? \"Will generate a new source list file\"\n                          : \"将生成新的源配置文件\";\n      chsrc_note2 (msg);\n    }\n\n  /* 反向引用需要escape */\n  char *codename = xy_run (\"sed -nr 's/VERSION_CODENAME=(.*)/\\\\1/p' \" ETC_OS_RELEASE, 0);\n\n  char *version_id = xy_run (\"sed -nr 's/VERSION_ID=\\\"(.*)\\\"/\\\\1/p' \" ETC_OS_RELEASE, 0);\n\n  double version = atof (version_id);\n\n  char *makeup = NULL;\n\n  if (debian_type == OS_Is_Ubuntu)\n    {\n      makeup = xy_str_gsub (RAWSTR_os_apt_based_ubuntu_old_source_list, \"@v@\", Chsrc_Version);\n      makeup = xy_str_gsub (makeup, \"@1@\", Chsrc_Maintain_URL);\n      makeup = xy_str_gsub (makeup, \"@2@\", codename);\n    }\n  else\n    {\n      if (version >= 12)  /* bookworm */\n        {\n          makeup = xy_str_gsub (RAWSTR_os_apt_based_debian_12_source_list, \"@v@\", Chsrc_Version);\n          makeup = xy_str_gsub (makeup, \"@1@\", Chsrc_Maintain_URL);\n          makeup = xy_str_gsub (makeup, \"@2@\", codename);\n        }\n      else if (version >= 11) /* bullseye */\n        {\n          makeup = xy_str_gsub (RAWSTR_os_apt_based_debian_11_source_list, \"@v@\", Chsrc_Version);\n          makeup = xy_str_gsub (makeup, \"@1@\", Chsrc_Maintain_URL);\n          makeup = xy_str_gsub (makeup, \"@2@\", codename);\n        }\n      else if (version >= 10) /* buster */\n        {\n          makeup = xy_str_gsub (RAWSTR_os_apt_based_debian_10_source_list, \"@v@\", Chsrc_Version);\n          makeup = xy_str_gsub (makeup, \"@1@\", Chsrc_Maintain_URL);\n          makeup = xy_str_gsub (makeup, \"@2@\", codename);\n        }\n      else\n        {\n          char *msg = ENGLISH ? \"Your Debian version is too low (<10) for chsrc to support\"\n                              : \"你的 Debian 版本过低 (<10)，暂不支持换源\";\n          chsrc_error (msg);\n          exit (Exit_Unsupported);\n        }\n    }\n\n  FILE *f = fopen (OS_Apt_SourceList, \"w\");\n  fwrite (makeup, strlen (makeup), 1, f);\n  fclose (f);\n  return false;\n}\n"
  },
  {
    "path": "src/recipe/os/APT/deepin.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_deepin, \"deepin\");\n\nvoid\nos_deepin_prelude ()\n{\n  chef_prep_this (os_deepin, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-26\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2024-09-14\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@G_I_Y\");\n  chef_set_sauciers (this, 1, \"@Yangmoooo\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://community-packages.deepin.com/deepin\", DelegateToUpstream},\n  {&Ali,              \"https://mirrors.aliyun.com/deepin\",            DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/deepin\",          DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/deepin\",          DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/deepin\",  DelegateToMirror},\n  {&Tencent,          \"https://mirrors.tencent.com/deepin\",          DelegateToMirror}\n  // {&Tencent_Intra, \"https://mirrors.tencentyun.com/deepin\",     DelegateToMirror},\n  /* 不启用原因：过慢 */\n  // {&Netease,       \"https://mirrors.163.com/deepin\",             DelegateToMirror},\n  /* 不启用原因：过慢 */\n  // {&Sohu,          \"https://mirrors.sohu.com/deepin\",            DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_deepin_getsrc(char *option)\n{\n  chsrc_view_file (OS_Apt_SourceList);\n}\n\n/**\n * HELP: 未经测试\n */\nvoid\nos_deepin_setsrc (char *option)\n{\n  chsrc_ensure_root();\n\n  chsrc_use_this_source (os_deepin);\n\n  chsrc_backup (OS_Apt_SourceList);\n\n  char *cmd = xy_strcat (3, \"sed -E -i \\'s@https?://.*/deepin/?@\",\n                              source.url,\n                              \"@g\\' \" OS_Apt_SourceList);\n\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_deepin_resetsrc (char *option)\n{\n  os_deepin_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/APT/openKylin.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * openKylin直接基于Linux内核开发，属于和Debian、openSUSE、Fedora、Arch\n * 同一级别的、根社区发布的系统\n * ------------------------------------------------------------*/\n\ndef_target(os_openkylin, \"openkylin\");\n\nvoid\nos_openkylin_prelude ()\n{\n  chef_prep_this (os_openkylin, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-06\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2023-09-29\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@G_I_Y\");\n  chef_set_sauciers (this, 1, \"@ccmywish\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://archive.openkylin.top/openkylin/\", DelegateToUpstream},\n  {&Ali,              \"https://mirrors.aliyun.com/openkylin/\",    DelegateToMirror},\n  {&Netease,          \"https://mirrors.163.com/openkylin/\",       DelegateToMirror}\n  def_sources_end()\n}\n\nvoid\nos_openkylin_getsrc (char *option)\n{\n  chsrc_view_file (OS_Apt_SourceList);\n}\n\nvoid\nos_openkylin_setsrc (char *option)\n{\n  chsrc_ensure_root();\n\n  chsrc_use_this_source (os_openkylin);\n\n  chsrc_backup (OS_Apt_SourceList);\n\n  char *cmd = xy_strcat (3, \"sed -E -i 's@https?://.*/openkylin/?@\", source.url, \"@g'\" OS_Apt_SourceList);\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"apt-get update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_openkylin_resetsrc (char *option)\n{\n  os_openkylin_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/APT/rawstr4c.h",
    "content": "#pragma once\n\n/**\n * Generated by rawstr4c v1.0.0-2025/08/09\n */\n\nchar RAWSTR_os_apt_based_ubuntu_old_source_list[] = \"\\x23\\x20\\x47\\x65\\x6e\\x65\\x72\\x61\\x74\\x65\\x64\\x20\\x62\\x79\\x20\\x63\\x68\\x73\\x72\\x63\\x20\\x40\\x76\\x40\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x75\\x62\\x75\\x6e\\x74\\x75\\x20\\x40\\x32\\x40\\x20\\x6d\\x61\\x69\\x6e\\x20\\x72\\x65\\x73\\x74\\x72\\x69\\x63\\x74\\x65\\x64\\x20\\x75\\x6e\\x69\\x76\\x65\\x72\\x73\\x65\\x20\\x6d\\x75\\x6c\\x74\\x69\\x76\\x65\\x72\\x73\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x75\\x62\\x75\\x6e\\x74\\x75\\x20\\x40\\x32\\x40\\x2d\\x75\\x70\\x64\\x61\\x74\\x65\\x73\\x20\\x6d\\x61\\x69\\x6e\\x20\\x72\\x65\\x73\\x74\\x72\\x69\\x63\\x74\\x65\\x64\\x20\\x75\\x6e\\x69\\x76\\x65\\x72\\x73\\x65\\x20\\x6d\\x75\\x6c\\x74\\x69\\x76\\x65\\x72\\x73\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x75\\x62\\x75\\x6e\\x74\\x75\\x20\\x40\\x32\\x40\\x2d\\x62\\x61\\x63\\x6b\\x70\\x6f\\x72\\x74\\x73\\x20\\x6d\\x61\\x69\\x6e\\x20\\x72\\x65\\x73\\x74\\x72\\x69\\x63\\x74\\x65\\x64\\x20\\x75\\x6e\\x69\\x76\\x65\\x72\\x73\\x65\\x20\\x6d\\x75\\x6c\\x74\\x69\\x76\\x65\\x72\\x73\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x75\\x62\\x75\\x6e\\x74\\x75\\x20\\x40\\x32\\x40\\x2d\\x73\\x65\\x63\\x75\\x72\\x69\\x74\\x79\\x20\\x6d\\x61\\x69\\x6e\\x20\\x72\\x65\\x73\\x74\\x72\\x69\\x63\\x74\\x65\\x64\\x20\\x75\\x6e\\x69\\x76\\x65\\x72\\x73\\x65\\x20\\x6d\\x75\\x6c\\x74\\x69\\x76\\x65\\x72\\x73\\x65\";\n\nchar RAWSTR_os_apt_based_debian_12_source_list[] = \"\\x23\\x20\\x47\\x65\\x6e\\x65\\x72\\x61\\x74\\x65\\x64\\x20\\x62\\x79\\x20\\x63\\x68\\x73\\x72\\x63\\x20\\x40\\x76\\x40\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x20\\x40\\x32\\x40\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x2d\\x66\\x69\\x72\\x6d\\x77\\x61\\x72\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x20\\x40\\x32\\x40\\x2d\\x75\\x70\\x64\\x61\\x74\\x65\\x73\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x2d\\x66\\x69\\x72\\x6d\\x77\\x61\\x72\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x20\\x40\\x32\\x40\\x2d\\x62\\x61\\x63\\x6b\\x70\\x6f\\x72\\x74\\x73\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x2d\\x66\\x69\\x72\\x6d\\x77\\x61\\x72\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x2d\\x73\\x65\\x63\\x75\\x72\\x69\\x74\\x79\\x20\\x40\\x32\\x40\\x2d\\x73\\x65\\x63\\x75\\x72\\x69\\x74\\x79\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x2d\\x66\\x69\\x72\\x6d\\x77\\x61\\x72\\x65\";\n\nchar RAWSTR_os_apt_based_debian_11_source_list[] = \"\\x23\\x20\\x47\\x65\\x6e\\x65\\x72\\x61\\x74\\x65\\x64\\x20\\x62\\x79\\x20\\x63\\x68\\x73\\x72\\x63\\x20\\x40\\x76\\x40\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x20\\x40\\x32\\x40\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x20\\x40\\x32\\x40\\x2d\\x75\\x70\\x64\\x61\\x74\\x65\\x73\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x20\\x40\\x32\\x40\\x2d\\x62\\x61\\x63\\x6b\\x70\\x6f\\x72\\x74\\x73\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x2d\\x73\\x65\\x63\\x75\\x72\\x69\\x74\\x79\\x20\\x40\\x32\\x40\\x2d\\x73\\x65\\x63\\x75\\x72\\x69\\x74\\x79\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\";\n\nchar RAWSTR_os_apt_based_debian_10_source_list[] = \"\\x23\\x20\\x47\\x65\\x6e\\x65\\x72\\x61\\x74\\x65\\x64\\x20\\x62\\x79\\x20\\x63\\x68\\x73\\x72\\x63\\x20\\x40\\x76\\x40\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x20\\x40\\x32\\x40\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x20\\x40\\x32\\x40\\x2d\\x75\\x70\\x64\\x61\\x74\\x65\\x73\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x20\\x40\\x32\\x40\\x2d\\x62\\x61\\x63\\x6b\\x70\\x6f\\x72\\x74\\x73\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\\x0a\\x64\\x65\\x62\\x20\\x40\\x31\\x40\\x2f\\x64\\x65\\x62\\x69\\x61\\x6e\\x2d\\x73\\x65\\x63\\x75\\x72\\x69\\x74\\x79\\x20\\x40\\x32\\x40\\x2f\\x75\\x70\\x64\\x61\\x74\\x65\\x73\\x20\\x6d\\x61\\x69\\x6e\\x20\\x63\\x6f\\x6e\\x74\\x72\\x69\\x62\\x20\\x6e\\x6f\\x6e\\x2d\\x66\\x72\\x65\\x65\";\n\n"
  },
  {
    "path": "src/recipe/os/APT/rawstr4c.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------------------------------------------------------------\n ! Config Type   : rawstr4c (Markdown)\n ! Config Authors: Aoran Zeng <ccmywish@qq.com>\n ! Contributors  :  Nil Null  <nil@null.org>\n ! Created On    : <2025-07-14>\n ! Last Modified : <2025-08-08>\n ! ---------------------------------------------------------- -->\n\n# rawstr4c input\n\n- prefix = `RAWSTR_os_apt_based`\n- output = `:global-variable-only-header`\n- translate = `:hex`\n- no-postfix = `true`\n\n\n\n## Ubuntu old source list\n\n```sh\n# Generated by chsrc @v@\ndeb @1@/ubuntu @2@ main restricted universe multiverse\ndeb @1@/ubuntu @2@-updates main restricted universe multiverse\ndeb @1@/ubuntu @2@-backports main restricted universe multiverse\ndeb @1@/ubuntu @2@-security main restricted universe multiverse\n```\n\n\n\n## Debian 12 source list\n\n```sh\n# Generated by chsrc @v@\ndeb @1@/debian @2@ main contrib non-free non-free-firmware\ndeb @1@/debian @2@-updates main contrib non-free non-free-firmware\ndeb @1@/debian @2@-backports main contrib non-free non-free-firmware\ndeb @1@/debian-security @2@-security main contrib non-free non-free-firmware\n```\n\n从 Debian 12 开始，开始有一项 `non-free-firmware`\n\n- https://wiki.debian.org/SourcesList\n- https://mirrors.tuna.tsinghua.edu.cn/help/debian/\n\n\n\n## Debian 11 source list\n\n```sh\n# Generated by chsrc @v@\ndeb @1@/debian @2@ main contrib non-free\ndeb @1@/debian @2@-updates main contrib non-free\ndeb @1@/debian @2@-backports main contrib non-free\ndeb @1@/debian-security @2@-security main contrib non-free\n```\n\n\n## Debian 10 source list\n\n```sh\n# Generated by chsrc @v@\ndeb @1@/debian @2@ main contrib non-free\ndeb @1@/debian @2@-updates main contrib non-free\ndeb @1@/debian @2@-backports main contrib non-free\ndeb @1@/debian-security @2@/updates main contrib non-free\n```\n\n上述 debian-security 这种写法是和 Debian 11 不同的，我们只支持到这里\n"
  },
  {
    "path": "src/recipe/os/Alpine-Linux.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_alpine, \"alpine\");\n\nvoid\nos_alpine_prelude ()\n{\n  chef_prep_this (os_alpine, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-24\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2024-09-14\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@Yangmoooo\");\n\n  chef_set_os_scope (this);\n\n  chef_allow_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"http://dl-cdn.alpinelinux.org/alpine\", FeedByPrelude},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/alpine\", FeedByPrelude},\n  {&Sjtug_Zhiyuan,    \"https://mirrors.sjtug.sjtu.edu.cn/alpine\", FeedByPrelude},\n  {&Sustech,          \"https://mirrors.sustech.edu.cn/alpine\", FeedByPrelude},\n  {&Zju,              \"https://mirrors.zju.edu.cn/alpine\", FeedByPrelude},\n  {&Lzuoss,           \"https://mirror.lzu.edu.cn/alpine\", FeedByPrelude},\n  {&Ali,              \"https://mirrors.aliyun.com/alpine\", FeedByPrelude},\n  {&Tencent,          \"https://mirrors.cloud.tencent.com/alpine\", FeedByPrelude},\n  {&Huawei,           \"https://mirrors.huaweicloud.com/alpine\", FeedByPrelude}\n  def_sources_end()\n\n  chef_set_rest_smURL_with_postfix (this, \"/latest-stable/releases/x86_64/alpine-standard-3.21.0-x86_64.iso\");\n}\n\n\nvoid\nos_alpine_getsrc (char *option)\n{\n  chsrc_view_file (\"/etc/apk/repositories\");\n}\n\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/alpine/\n */\nvoid\nos_alpine_setsrc (char *option)\n{\n  // chsrc_ensure_root(); // HELP: 不确定是否需要root\n\n  chsrc_use_this_source (os_alpine);\n\n  char* cmd = xy_strcat (3,\n            \"sed -i 's#https\\\\?://dl-cdn.alpinelinux.org/alpine#\", source.url, \"#g' /etc/apk/repositories\"\n            );\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_run (\"apk update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/BSD/FreeBSD.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_freebsd, \"freebsd\");\n\nvoid\nos_freebsd_prelude ()\n{\n  chef_prep_this (os_freebsd, s);\n\n  chef_set_recipe_created_on   (this, \"2023-09-03\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2023-09-27\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 2, \"@ccmywish\", \"@G_I_Y\");\n  chef_set_sauciers (this, 1, \"@hezonglun\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n\n  // 2023-09-24: 以下三个USTC, NJU, Netease 均维护了 freebsd-pkg freebsd-ports\n  // 2023-09-27: 请务必保持Nju前面有至少一个镜像，原因请查看 freebsd 的换源函数\n  def_sources_begin()\n  {&UpstreamProvider, \"pkg.freebsd.org\",     DelegateToUpstream},\n  {&Ustc,             \"mirrors.ustc.edu.cn\", DelegateToMirror},\n  {&Nju,              \"mirror.nju.edu.cn\",   DelegateToMirror},\n  {&Netease,          \"mirrors.163.com\",     DelegateToMirror},\n  def_sources_end()\n}\n\n/**\n * @consult\n *  1. https://book.bsdcn.org/di-3-zhang-ruan-jian-yuan-ji-bao-guan-li-qi/di-3.2-jie-freebsd-huan-yuan-fang-shi.html\n *  2. https://help.mirrors.cernet.edu.cn/FreeBSD-ports/\n *\n * 据 @ykla,\n *   FreeBSD 有五类源：pkg、ports、port、portsnap、update，其中 portsnap 在 FreeBSD 14 已经被移除了\n */\nvoid\nos_freebsd_setsrc (char *option)\n{\n  // 据 @ykla，FreeBSD不自带sudo，但是我们依然要保证是root权限\n  chsrc_ensure_root ();\n\n  chef_use_this (os_freebsd);\n  int index = use_specific_mirror_or_auto_select (option, this);\n\n  Source_t source = this->sources[index];\n  chsrc_confirm_source(&source);\n\n  chsrc_log2 (\"1. 添加 freebsd-pkg 源 (二进制安装包)\");\n  chsrc_ensure_dir (\"/usr/local/etc/pkg/repos\");\n\n  char *conf = xy_strcat (3, \"/usr/local/etc/pkg/repos/\", source.mirror->code, \".conf\");\n\n  char *pkg_content = xy_strcat (4,\n                      source.mirror->code, \": { \\n\"\n                      \"  url: \\\"http://\", source.url, \"/freebsd-pkg/${ABI}/latest\\\",\\n\"\n                      \"}\\n\"\n                      \"FreeBSD: { enabled: no }\"\n                    );\n\n  chsrc_overwrite_file (pkg_content, conf);\n  chsrc_note2 (\n    xy_strcat (3, \"若要使用季度分支，请在\", conf ,\"中将latest改为quarterly\"));\n\n  chsrc_alert2 (\"若要使用HTTPS源，请先安装securtiy/ca_root_ns，并将'http'改成'https'，最后使用'pkg update -f'刷新缓存即可\\n\");\n  br();\n\n  chsrc_log2 (\"2. 修改 freebsd-ports 源\");\n  // @ccmywish: 2023-09-27 据 @ykla , NJU的freebsd-ports源没有设置 Git，\n  //                       但是我认为由于使用Git还是要比非Git方便许多，我们尽可能坚持使用Git\n  //                       而 gitup 又要额外修改它自己的配置，比较麻烦\n  bool git_exist = query_program_exist (xy_quiet_cmd (\"git version\"), \"git\", Noisy_When_Exist|Noisy_When_NonExist);\n  if (git_exist)\n    {\n      if (xy_streql(\"nju\",source.mirror->code))\n        {\n          source = this->sources[index-1]; // 使用NJU的前一个源，即USTC源\n        }\n      char *git_cmd = xy_strcat (3, \"git clone --depth 1 https://\", source.url, \"/freebsd-ports/ports.git /usr/ports\");\n      chsrc_run (git_cmd, RunOpt_Default);\n      source = this->sources[index]; // 恢复至选中的源\n      chsrc_alert2 (\"下次更新请使用 git -C /usr/ports pull 而非使用 gitup\");\n    }\n  else\n    {\n      char *fetch  = xy_strcat (3, \"fetch https://\", source.url, \"/freebsd-ports/ports.tar.gz\");  // 70多MB\n      char *unzip  = \"tar -zxvf ports.tar.gz -C /usr/ports\";\n      char *delete = \"rm ports.tar.gz\";\n      chsrc_run (fetch, RunOpt_Default);\n      chsrc_run (unzip, RunOpt_Default);\n      chsrc_run (delete, RunOpt_Default);\n      chsrc_log2 (\"下次更新请重新下载内容至 /usr/ports\");\n    }\n\n\n  chsrc_log2 (\"3. 指定 port 源\");\n  // https://help.mirrors.cernet.edu.cn/FreeBSD-ports/\n  chsrc_backup (\"/etc/make.conf\");\n\n  char *ports = xy_strcat (3, \"MASTER_SITE_OVERRIDE?=http://\", source.url, \"/freebsd-ports/distfiles/${DIST_SUBDIR}/\\n\");\n  chsrc_append_to_file (ports, \"/etc/make.conf\");\n\n\n  /* 不再换 portsnap */\n  /*\n    chsrc_backup (\"/etc/portsnap.conf\");\n\n    char *portsnap =xy_strcat(3,\"s@(.*)SERVERNAME=[\\\\.|a-z|A-Z]*@\\\\1SERVERNAME=\", source.url,\n                                \"@g < /etc/portsnap.conf.bak\");\n\n    chsrc_overwrite_file (portsnap, \"/etc/portsnap.conf\");\n\n    chsrc_log2 (\"portsnap sources changed\");\n    chsrc_log2 (\"获取portsnap更新使用此命令: 'portsnap fetch extract'\");\n  */\n\n\n  // HELP: 暂时没有源提供\n  chsrc_alert2 (\"4. 抱歉，目前境内无 freebsd-update 源，若存在请报告issue，谢谢\");\n  /*\n    chsrc_log2 (\"3. 修改 freebsd-update 源\");\n\n    char *update_cp = \"cp /etc/freebsd-update.conf /etc/freebsd-update.conf.bak\";\n    chsrc_run (update_cp, RunOpt_Default);\n\n    char *update =xy_strcat (3,\"s@(.*)SERVERNAME [\\\\.|a-z|A-Z]*@\\\\1SERVERNAME \",\n                                 source.url,\n                                \"@g < /etc/freebsd-update.conf.bak\");\n\n    chsrc_overwrite_file (update, \"/etc/freebsd-update.conf\");\n  */\n\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/BSD/NetBSD.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_netbsd, \"netbsd\");\n\nvoid\nos_netbsd_prelude ()\n{\n  chef_prep_this (os_netbsd, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-05\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-07-31\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 2, \"@ccmywish\", \"@G_I_Y\");\n  chef_set_sauciers (this, 1, \"@hezonglun\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"http://ftp.netbsd.org/pub/pkgsrc/packages/NetBSD/\",     DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/pkgsrc/packages/NetBSD/\", DelegateToMirror},\n  {&Ali,              \"https://mirrors.aliyun.com/pkgsrc/packages/NetBSD/\",  DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/pkgsrc/packages/NetBSD/\", DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/pkgsrc/packages/NetBSD/\", DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn/pkgsrc/packages/NetBSD/\",    DelegateToMirror},\n  {&Iscas,            \"https://mirror.iscas.ac.cn/pkgsrc/packages/NetBSD/\",  DelegateToMirror},\n  {&Tencent,          \"https://mirrors.tencent.com/pkgsrc/packages/NetBSD/\", DelegateToMirror},\n  // {&Tencent_Intra, \"https://mirrors.tencentyun.com/pkgsrc/packages/NetBSD/\", DelegateToMirror},\n  {&Netease,          \"https://mirrors.163.com/pkgsrc/packages/NetBSD/\",     DelegateToMirror},\n  {&Sohu,             \"https://mirrors.sohu.com/pkgsrc/packages/NetBSD/\",    DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_netbsd_getsrc (char *option)\n{\n  chsrc_view_file (\"/usr/pkg/etc/pkgin/repositories.conf\");\n}\n\n\n/**\n * @consult\n * 1. https://mirrors.tuna.tsinghua.edu.cn/help/pkgsrc/\n * 2. https://book.bsdcn.org/di-27-zhang-netbsd/di-27.2-jie-huan-yuan-yu-bao-guan-li-qi.html\n *\n * 根据 @ykla\n *    NetBSD 默认状态下没有 pkgsrc，用户可能安装了也可能没安装\n */\nvoid\nos_netbsd_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_netbsd);\n\n  chsrc_backup (\"/usr/pkg/etc/pkgin/repositories.conf\");\n\n  char *arch = chsrc_get_cpuarch ();\n  char *vercmd  = \"cat /etc/os-release | grep \\\"VERSION=\\\" | grep -Po \\\"[8-9].[0-9]+\\\"\";\n  char *version = xy_run (vercmd, 0);\n\n  char *url = xy_strcat (5, hp_ensure_trailing_slash (source.url), arch, \"/\", version, \"/All\");\n  chsrc_overwrite_file (url, \"/usr/pkg/etc/pkgin/repositories.conf\");\n\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/BSD/OpenBSD.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_openbsd, \"openbsd\");\n\nvoid\nos_openbsd_prelude ()\n{\n  chef_prep_this (os_openbsd, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-03\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-07-31\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 2, \"@G_I_Y\", \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@hezonglun\");\n\n  chef_set_os_scope (this);\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://cdn.openbsd.org/pub/OpenBSD/\",   DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/OpenBSD/\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/OpenBSD/\",   DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/OpenBSD/\", DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn/OpenBSD/\",    DelegateToMirror},\n  {&Nyist,            \"https://mirror.nyist.edu.cn/OpenBSD/\",  DelegateToMirror},\n  {&Sjtug_Siyuan,     \"https://mirror.sjtu.edu.cn/OpenBSD/\",   DelegateToMirror},\n  {&Iscas,            \"https://mirror.iscas.ac.cn/OpenBSD/\",   DelegateToMirror},\n  {&Cqupt,            \"https://mirrors.cqupt.edu.cn/openbsd/\", DelegateToMirror},\n  {&Ali,              \"https://mirrors.aliyun.com/OpenBSD/\",   DelegateToMirror},\n  {&Tencent,          \"https://mirrors.tencent.com/OpenBSD/\",  DelegateToMirror},\n  // {&Tencent_Intra, \"https://mirrors.tencentyun.com/OpenBSD/\", DelegateToMirror},\n  {&Netease,          \"https://mirrors.163.com/OpenBSD/\",      DelegateToMirror},\n  {&Sohu,             \"https://mirrors.sohu.com/OpenBSD/\",     DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_openbsd_getsrc (char *option)\n{\n  chsrc_view_file (\"/etc/installurl\");\n}\n\n\n/**\n * @consult\n * 1. https://mirrors.tuna.tsinghua.edu.cn/help/openbsd/\n * 2. https://book.bsdcn.org/di-26-zhang-openbsd/di-26.2-jie-pei-zhi.html\n */\nvoid\nos_openbsd_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_openbsd);\n\n  chsrc_backup (\"/etc/installurl\");\n  chsrc_overwrite_file (source.url, \"/etc/installurl\");\n\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/Gentoo-Linux.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_gentoo, \"gentoo\");\n\nvoid\nos_gentoo_prelude ()\n{\n  chef_prep_this (os_gentoo, s);\n\n  chef_set_recipe_created_on   (this, \"2023-09-05\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-06-20\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@G_I_Y\");\n  chef_set_sauciers (this, 1, \"@ccmywish\");\n\n  chef_set_os_scope (this);\n\n  chef_allow_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"rsync://rsync.gentoo.org/gentoo-portage\", DelegateToUpstream},\n  {&Ali,              \"mirrors.aliyun.com\", DelegateToMirror},\n  {&Bfsu,             \"mirrors.bfsu.edu.cn\", DelegateToMirror},\n  {&Ustc,             \"mirrors.ustc.edu.cn\", DelegateToMirror},\n  {&Tuna,             \"mirrors.tuna.tsinghua.edu.cn\", DelegateToMirror},\n  {&Tencent,          \"mirrors.tencent.com\", DelegateToMirror}\n  def_sources_end()\n}\n\n\n/**\n * HELP: 未经测试\n */\nvoid\nos_gentoo_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_gentoo);\n\n  chsrc_backup (\"/etc/portage/repos.conf/gentoo.conf\");\n\n  char *cmd = xy_strcat (3, \"sed -i \\\"s#rsync://.*/gentoo-portage#rsync://\",\n                             source.url,\n                            \"gentoo-portage#g\");\n  chsrc_run (cmd, RunOpt_Default);\n\n  char *w = xy_strcat (3, \"GENTOO_MIRRORS=\\\"https://\", source.url, \"gentoo\\\"\\n\");\n\n  chsrc_append_to_file (w, \"/etc/portage/make.conf\");\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/OpenWrt.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_openwrt, \"openwrt/opkg/LEDE\");\n\nvoid\nos_openwrt_prelude ()\n{\n  chef_prep_this (os_openwrt, gsr);\n\n  chef_set_recipe_created_on   (this, \"2024-08-08\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2024-12-14\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 2, \"@Yangmoooo\", \"@happy-game\");\n\n  chef_set_os_scope (this);\n\n  chef_allow_english(this);\n  chef_allow_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://downloads.openwrt.org\", DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/openwrt\", DelegateToMirror},\n  {&Ali,              \"https://mirrors.aliyun.com/openwrt\", DelegateToMirror},\n  {&Tencent,          \"https://mirrors.cloud.tencent.com/openwrt\", DelegateToMirror},\n  {&Tuna,             \"https://mirror.tuna.tsinghua.edu.cn/openwrt\", DelegateToMirror},\n  {&Sjtug_Zhiyuan,    \"https://mirror.sjtu.edu.cn/openwrt\", DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/openwrt\", DelegateToMirror},\n  {&Pku,              \"https://mirrors.pku.edu.cn/openwrt\", DelegateToMirror},\n  {&Sustech,          \"https://mirrors.sustech.edu.cn/openwrt\", DelegateToMirror}\n  def_sources_end()\n\n  chef_set_provider_smURL (&UpstreamProvider, \"https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz\");\n}\n\n\n#define OS_OpenWRT_SourceConfig \"/etc/opkg/distfeeds.conf\"\n\nvoid\nos_openwrt_getsrc (char *option)\n{\n  chsrc_view_file (OS_OpenWRT_SourceConfig);\n}\n\n/**\n * @consult\n *    1. https://mirror.tuna.tsinghua.edu.cn/help/openwrt/\n *    2. https://github.com/RubyMetric/chsrc/issues/153#issuecomment-2543077933\n */\nvoid\nos_openwrt_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_openwrt);\n\n  chsrc_backup (OS_OpenWRT_SourceConfig);\n\n  char *cmd = xy_strcat (3, \"sed -E -i 's@https?://.*/releases@\", source.url, \"/releases@g' \" OS_OpenWRT_SourceConfig);\n\n  chsrc_run (cmd, RunOpt_No_Last_New_Line);\n  chsrc_run (\"opkg update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_openwrt_resetsrc (char *option)\n{\n  os_openwrt_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/Solus.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_solus, \"solus\");\n\nvoid\nos_solus_prelude ()\n{\n  chef_prep_this (os_solus, s);\n\n  chef_set_recipe_created_on   (this, \"2023-09-29\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2023-09-29\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://packages.getsol.us/shannon/eopkg-index.xml.xz\", DelegateToUpstream},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/solus/packages/shannon/eopkg-index.xml.xz\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/solus/packages/shannon/eopkg-index.xml.xz\", DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn/solus/packages/shannon/eopkg-index.xml.xz\", DelegateToMirror}\n  def_sources_end()\n}\n\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/solus/\n */\nvoid\nos_solus_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_solus);\n\n  char *cmd = xy_2strcat (\"eopkg add-repo Solus \", source.url);\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/Void-Linux.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_voidlinux, \"voidlinux\");\n\nvoid\nos_voidlinux_prelude ()\n{\n  chef_prep_this (os_voidlinux, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-24\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2024-12-18\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@Yangmoooo\");\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://repo-default.voidlinux.org\", FeedByPrelude},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/voidlinux\", FeedByPrelude},\n  {&Sjtug_Zhiyuan,    \"https://mirror.sjtu.edu.cn/voidlinux\", FeedByPrelude},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/voidlinux\", FeedByPrelude}\n  def_sources_end()\n\n  chef_set_rest_smURL_with_postfix (this, \"/live/20240314/void-live-x86_64-musl-20240314-xfce.iso\");\n}\n\n\nvoid\nos_voidlinux_getsrc (char *option)\n{\n  char* cmd = \"xbps-query -L\";\n  chsrc_run (cmd, RunOpt_No_Last_New_Line);\n}\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/voidlinux/\n */\nvoid\nos_voidlinux_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_voidlinux);\n\n  chsrc_ensure_dir (\"/etc/xbps.d\");\n  char *cmd = \"cp /usr/share/xbps.d/*-repository-*.conf /etc/xbps.d/\";\n  chsrc_run (cmd, RunOpt_Default);\n\n  cmd = xy_strcat (3,\n            \"sed -i 's|https://repo-default.voidlinux.org|\", source.url, \"|g' /etc/xbps.d/*-repository-*.conf\"\n            );\n  chsrc_run (cmd, RunOpt_Default);\n\n  cmd = xy_strcat (3,\n            \"sed -i 's|https://alpha.de.repo.voidlinux.org|\", source.url, \"|g' /etc/xbps.d/*-repository-*.conf\"\n            );\n\n  chsrc_note2 (\"若报错可尝试使用以下命令:\");\n  p (cmd);\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_voidlinux_resetsrc (char *option)\n{\n  os_voidlinux_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/YUM/AlmaLinux.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_almalinux, \"alma/almalinux\");\n\nvoid\nos_almalinux_prelude ()\n{\n  chef_prep_this (os_almalinux, s);\n\n  chef_set_recipe_created_on   (this, \"2024-06-12\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-08-22\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@Yangmoooo\");\n\n  chef_set_os_scope (this);\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"http://repo.almalinux.org/almalinux\",  DelegateToUpstream},\n  {&Ali,              \"https://mirrors.aliyun.com/almalinux\", FeedByPrelude},\n  {&Volcengine,       \"https://mirrors.volces.com/almalinux\", FeedByPrelude},\n  {&Sjtug_Zhiyuan,    \"https://mirrors.sjtug.sjtu.edu.cn/almalinux\", FeedByPrelude},\n  {&Zju,              \"https://mirrors.zju.edu.cn/almalinux\",        FeedByPrelude},\n  {&Nju,              \"https://mirror.nju.edu.cn/almalinux\",         FeedByPrelude}\n  def_sources_end()\n\n#define link \"/9.6/isos/x86_64/AlmaLinux-9-latest-x86_64-minimal.iso\"\n  chef_set_rest_smURL_with_postfix (this, link);\n  chef_set_provider_smURL (&UpstreamProvider, \"https://raw.repo.almalinux.org/almalinux\" link);\n#undef link\n}\n\n/**\n * @consult: https://developer.aliyun.com/mirror/almalinux\n */\nvoid\nos_almalinux_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_almalinux);\n\n  char *cmd = xy_strcat (3,\n    \"sed -e 's|^mirrorlist=|#mirrorlist=|g' -e 's|^#\\\\s*baseurl=https://repo.almalinux.org/almalinux|baseurl=\", source.url, \"|g'  -i.bak  /etc/yum.repos.d/almalinux*.repo\");\n\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"dnf makecache\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/YUM/Anolis-OS.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_anolis, \"anolis/openanolis\");\n\nvoid\nos_anolis_prelude ()\n{\n  chef_prep_this (os_anolis, s);\n\n  chef_set_recipe_created_on   (this, \"2023-09-24\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2024-06-12\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_os_scope (this);\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://mirrors.openanolis.cn/anolis\", DelegateToUpstream},\n  {&Ali,              \"https://mirrors.aliyun.com/anolis\",  DelegateToMirror},\n  {&Hust,             \"https://mirrors.hust.edu.cn/anolis\", DelegateToMirror}\n  def_sources_end()\n}\n\n\n/**\n * @consult: https://mirrors.hust.edu.cn/docs/anolis\n */\nvoid\nos_anolis_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_anolis);\n\n  char *cmd = xy_strcat (3, \"sed -i.bak -E 's|https?://(mirrors\\\\.openanolis\\\\.cn/anolis)|\", source.url, \"|g' /etc/yum.repos.d/*.repo\");\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_run (\"dnf makecache\", RunOpt_Default);\n  chsrc_run (\"dnf update\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/YUM/Fedora-Linux.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_fedora, \"fedora\");\n\nvoid\nos_fedora_prelude ()\n{\n  chef_prep_this (os_fedora, sr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-26\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-06-20\");\n\n  chef_set_chef (this, \"@happy-game\");\n  chef_set_cooks (this, 2, \"@G_I_Y\", \"@happy-game\");\n  chef_set_sauciers (this, 1, \"@ccmywish\");\n\n  chef_set_os_scope (this);\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"http://download.example/pub/fedora/linux\", DelegateToUpstream},\n  {&Ali,              \"https://mirrors.aliyun.com/fedora\",        DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/fedora\",       DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/fedora\",       DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/fedora\", DelegateToMirror},\n  {&Tencent,          \"https://mirrors.tencent.com/fedora\",       DelegateToMirror}\n  // {&Tencent_Intra, \"https://mirrors.tencentyun.com/fedora\",    DelegateToMirror},\n\n  /* 不启用原因：过慢 */\n  // {&Netease,          \"https://mirrors.163.com/fedora\",        DelegateToMirror},\n  /* 不启用原因：过慢 */\n  // {&Sohu,             \"https://mirrors.sohu.com/fedora\",        DelegateToMirror}\"\n  def_sources_end()\n}\n\n\n/**\n * @note fedora 38 及以下版本暂不支持\n *\n * @consult https://mirrors.ustc.edu.cn/help/fedora.html\n */\nvoid\nos_fedora_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_fedora);\n\n  chsrc_alert2 (\"Fedora 38 及以下版本暂不支持\");\n\n  chsrc_backup (\"/etc/yum.repos.d/fedora.repo\");\n  chsrc_backup (\"/etc/yum.repos.d/fedora-updates.repo\");\n\n  // 取消对 baseurl 的注释\n  char* cmd = xy_strcat (5, \"sed \",\n         \"-i 's|^#baseurl=|baseurl=\",\n         \"|g' \",\n         \"/etc/yum.repos.d/fedora.repo \",\n         \"/etc/yum.repos.d/fedora-updates.repo\");\n  chsrc_run (cmd, RunOpt_Default);\n\n  // 替换\n  // (1) baseurl=<<URL>>/releases/...\n  // (2) baseurl=<<URL>>/updates/...\n  cmd = xy_strcat (7, \"sed \",\n         \"-i -E 's!^baseurl=.*?/(releases|updates)/!baseurl=\",\n         source.url,\n         \"/\\\\1/\",\n         \"!g' \",\n         \"/etc/yum.repos.d/fedora.repo \",\n         \"/etc/yum.repos.d/fedora-updates.repo\");\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_alert2 (\"已更换baseurl, 但Fedora默认会优先使用metalink来匹配最快的源, 若在获取metadata时速度较慢可自行将其注释:\");\n  chsrc_log2 (\"(1) /etc/yum.repos.d/fedora.repo\");\n  chsrc_log2 (\"(2) /etc/yum.repos.d/fedora-updates.repo\");\n\n  chsrc_run (\"dnf makecache\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_fedora_resetsrc (char *option)\n{\n  os_fedora_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/YUM/Rocky-Linux.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_rockylinux, \"rocky/rockylinux\");\n\nvoid\nos_rockylinux_prelude ()\n{\n  chef_prep_this (os_rockylinux, sr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-24\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-06-20\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@happy-game\");\n\n  chef_set_os_scope (this);\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://dl.rockylinux.org\",                 DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/rocky\",       DelegateToMirror},\n  {&Ali,              \"https://mirrors.aliyun.com/rockylinux\",      DelegateToMirror},\n  {&Volcengine,       \"https://mirrors.volces.com/rockylinux\",      DelegateToMirror},\n  {&Sjtug_Zhiyuan,    \"https://mirror.sjtu.edu.cn/rocky\",          DelegateToMirror},\n  {&Sustech,          \"https://mirrors.sustech.edu.cn/rocky-linux\", DelegateToMirror},\n  {&Zju,              \"https://mirrors.zju.edu.cn/rocky\",          DelegateToMirror},\n  {&Lzuoss,           \"https://mirror.lzu.edu.cn/rocky\",           DelegateToMirror},\n  /* 不启用原因：过慢 */\n  // {&Netease,          \"https://mirrors.163.com/rocky\",      DelegateToMirror},\n  /* 不启用原因：过慢 */\n  // {&Sohu,             \"https://mirrors.sohu.com/Rocky\",     DelegateToMirror}\n  def_sources_end()\n}\n\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/rocky/\n */\nvoid\nos_rockylinux_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_rockylinux);\n\n  char *version_str = xy_run (\"sed -nr 's/ROCKY_SUPPORT_PRODUCT_VERSION=\\\"(.*)\\\"/\\\\1/p' \" ETC_OS_RELEASE, 0);\n  double version = atof (version_str);\n\n  char *cmd = NULL;\n\n  if (version < 9)\n    {\n      cmd = xy_strcat (3,\n                      \"sed -e 's|^mirrorlist=|#mirrorlist=|g' \"\n                      \"-e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=\", source.url, \"|g' \"\n                      \"-i.bak /etc/yum.repos.d/Rocky-*.repo\"\n                      );\n                      // Rocky-AppStream.repo\n                      // Rocky-BaseOS.repo\n                      // Rocky-Extras\n                      // Rocky-PowerTools\n    }\n  else\n    {\n      cmd = xy_strcat (3,\n                      \"sed -e 's|^mirrorlist=|#mirrorlist=|g' \"\n                      \"-e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=\", source.url, \"|g' \"\n                      \"-i.bak /etc/yum.repos.d/rocky-extras.repo /etc/yum.repos.d/rocky.repo\"\n                      );\n    }\n\n\n  chsrc_run (cmd, RunOpt_Default);\n  chsrc_run (\"dnf makecache\", RunOpt_No_Last_New_Line);\n\n  chsrc_conclude (&source);\n}\n\n\nvoid\nos_rockylinux_resetsrc (char *option)\n{\n  os_rockylinux_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/YUM/common.h",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Authors  : Aoran Zeng <ccmywish@qq.com>\n * Contributors  :  Nil Null  <nil@null.org>\n *               |\n * Created On    : <2024-08-16>\n * Last Modified : <2024-12-18>\n * ------------------------------------------------------------*/\n\n// #define OS_Yum_SourceList    \"/etc/yum.repos\"\n#define OS_Yum_SourceList_D     \"/etc/yum.repos.d/\"\n\n#define OS_openEuler_SourceList OS_Yum_SourceList_D \"openEuler.repo\"\n"
  },
  {
    "path": "src/recipe/os/YUM/openEuler.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_openeuler, \"openeuler\");\n\nvoid\nos_openeuler_prelude ()\n{\n  chef_prep_this (os_openeuler, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-06\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-06-20\");\n\n  chef_set_cooks (this, 1, \"@G_I_Y\");\n  chef_set_chef (this, NULL);\n  chef_set_sauciers (this, 3, \"@ccmywish\", \"@Yangmoooo\", \"@happy-game\");\n\n  chef_set_os_scope (this);\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://repo.openeuler.org/\",               FeedByPrelude},\n  {&Ali,              \"https://mirrors.aliyun.com/openeuler/\",     FeedByPrelude},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/openeuler/\",    FeedByPrelude},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/openeuler/\",    FeedByPrelude},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/openeuler/\", FeedByPrelude},\n  {&Tencent,          \"https://mirrors.tencent.com/openeuler/\",    FeedByPrelude}\n  // {&Tencent_Intra, \"https://mirrors.tencentyun.com/openeuler/\", FeedByPrelude},\n\n  /* 不启用原因：过慢 */\n  // {&Netease,          \"https://mirrors.163.com/openeuler/\",  FeedByPrelude}\n  /* 不启用原因：过慢 */\n  // {&Sohu,             \"https://mirrors.sohu.com/openeuler/\", FeedByPrelude}\n  def_sources_end()\n\n  chef_set_rest_smURL_with_postfix (this, \"https://repo.openeuler.org/openEuler-24.03-LTS/ISO/x86_64/openEuler-24.03-LTS-netinst-x86_64-dvd.iso\");\n}\n\n\n/**\n * chsrc get openeuler\n */\nvoid\nos_openeuler_getsrc (char *option)\n{\n  chsrc_view_file (OS_openEuler_SourceList);\n}\n\n\n/**\n * chsrc set openeuler\n */\nvoid\nos_openeuler_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_openeuler);\n\n  chsrc_backup (OS_openEuler_SourceList);\n\n  // 替换 baseurl=<<URL>>/openEuler-xx.xx/...\n  // openEuler-xx.xx 为 openEuler 版本号\n  // sed -E 's!^baseurl=.*?/openEuler-([^/]+)!baseurl=$(source.url)/openEuler-\\1/!g' OS_openEuler_SourceList\n  char* cmd = xy_strcat (6, \"sed \",\n         \"-i -E 's!^baseurl=.*?/openEuler-([^/]+)!baseurl=\",\n         source.url,\n         \"openEuler-\\\\1\",\n         \"!g' \",\n         OS_openEuler_SourceList);\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_run (\"dnf makecache\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\n/**\n * chsrc reset openeuler\n */\nvoid\nos_openeuler_resetsrc (char *option)\n{\n  os_openeuler_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/os/openSUSE.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_opensuse, \"opensuse/opensuse-leap/opensuse-tumbleweed\");\n\nvoid\nos_opensuse_prelude ()\n{\n  chef_prep_this (os_opensuse, s);\n\n  chef_set_recipe_created_on   (this, \"2023-09-17\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-06-20\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 2, \"@ccmywish\", \"@G_I_Y\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_os_scope (this);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note(this, NULL, NULL);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://download.opensuse.org/\", DelegateToUpstream},\n  {&Ali,              \"https://mirrors.aliyun.com/opensuse\", DelegateToMirror},\n  {&Volcengine,       \"https://mirrors.volces.com/opensuse\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/opensuse\", DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/opensuse\", DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/opensuse\", DelegateToMirror},\n  {&Tencent,          \"https://mirrors.tencent.com/opensuse\", DelegateToMirror}\n  def_sources_end()\n}\n\n\n/**\n * @consult https://mirrors.tuna.tsinghua.edu.cn/help/opensuse/\n */\nvoid\nos_opensuse_setsrc (char *option)\n{\n  // chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_opensuse);\n\n  while (1) {\n    chsrc_note2 (\"请选择你的操作系统为:\");\n    printf (\"%s\",\n      \"1. openSUSE Leap\\n\"\n      \"2. openSUSE Tumbleweed\\n\"\n      \"\\n\"\n      \"==> \");\n\n    int choice = 0;\n\n    /* 接受到一个数字时返回1，非法为0，流结束为-1 */\n    if (scanf (\"%d\", &choice) != 1)\n      {\n        /* 清除输入缓冲区 */\n        int ch;\n        while ((ch = getchar()) != '\\n' && ch != EOF);\n        chsrc_error2 (\"输入无效！请输入数字\");\n        continue;\n      }\n    if (choice == 1)\n      {\n        char *script = xy_str_gsub (RAWSTR_os_openSUSE_leap_in_bash, \"@url@\", source.url);\n        chsrc_run_as_bash_file (script);\n        break;\n      }\n    if (choice == 2)\n      {\n        char *script = xy_str_gsub (RAWSTR_os_openSUSE_tumbleweed_in_bash, \"@url@\", source.url);\n        chsrc_run_as_bash_file (script);\n        break;\n      }\n    else\n      {\n        chsrc_error2 (\"无效的选择，请输入 1 或 2 \");\n      }\n  }\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/pacman/Arch-Linux.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_arch, \"arch/archlinux\");\n\n#define OS_Pacman_MirrorList \"/etc/pacman.d/mirrorlist\"\n#define OS_Pacman_ArchLinuxCN_MirrorList \"/etc/pacman.conf\"\n\nvoid\nos_arch_prelude ()\n{\n  chef_prep_this (os_arch, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-05\");\n  chef_set_recipe_last_updated (this, \"2025-10-30\");\n  chef_set_sources_last_updated (this, \"2025-06-20\");\n\n  chef_set_chef (this, \"@happy-game\");\n  chef_set_cooks (this, 2, \"@ccmywish\", \"@G_I_Y\");\n  chef_set_sauciers (this, 2, \"@happy-game\", \"@Young-Lord\");\n\n  chef_set_os_scope (this);\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note (this,\n    \"可额外使用 chsrc set archlinuxcn 来更换 Arch Linux CN Repository 源\",\n    \"You can additionally use chsrc set archlinuxcn to change Arch Linux CN Repository source\");\n\n  /**\n   * @note 不要给后面加 / ，因为ARM情况下，还要额外加一个 arm 后缀\n   */\n  def_sources_begin()\n  {&UpstreamProvider, \"https://repo.archlinux.org\",            DelegateToUpstream},\n  {&Ali,              \"https://mirrors.aliyun.com/archlinux\",  DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/archlinux\", DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/archlinux\", DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/archlinux\", DelegateToMirror},\n  {&Sjtug_Siyuan,     \"https://mirror.sjtu.edu.cn/archlinux\", DelegateToMirror},\n  {&Tencent,          \"https://mirrors.tencent.com/archlinux\", DelegateToMirror},\n  // {&Tencent_Intra, \"https://mirrors.tencentyun.com/archlinux\", DelegateToMirror},\n  {&Huawei,           \"https://mirrors.huaweicloud.com/archlinux\", DelegateToMirror},\n\n  /* 不启用原因：过慢 */\n  // {&Netease,          \"https://mirrors.163.com/archlinux\", DelegateToMirror},\n  /* 不启用原因：过慢 */\n  // {&Sohu,          \"https://mirrors.sohu.com/archlinux\",   DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_arch_getsrc (char *option)\n{\n  chsrc_view_file (OS_Pacman_MirrorList);\n}\n\n\n/**\n * @consult\n *   1. https://mirrors.tuna.tsinghua.edu.cn/help/archlinux/\n *   2. https://mirrors.tuna.tsinghua.edu.cn/help/archlinuxarm/\n */\nvoid\nos_arch_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_arch);\n\n  chsrc_backup (OS_Pacman_MirrorList);\n\n  bool  is_x86 = false;\n  char *to_write = NULL;\n  char *arch = chsrc_get_cpuarch ();\n\n  if (strncmp(arch, \"x86_64\", 6)==0)\n    {\n      is_x86 = true;\n      to_write = xy_strcat (3, \"Server = \", source.url, \"/$repo/os/$arch\\n\");\n    }\n  else\n    {\n      is_x86 = false;\n      to_write = xy_strcat (3, \"Server = \", source.url, \"arm/$arch/$repo\\n\");\n    }\n\n  /* 配置文件中，越前面的优先级越高 */\n  chsrc_prepend_to_file (to_write, OS_Pacman_MirrorList);\n\n  if (is_x86)\n    {\n      chsrc_run (\"pacman -Syyu\", RunOpt_No_Last_New_Line);\n    }\n  else\n    {\n      chsrc_run (\"pacman -Syy\", RunOpt_No_Last_New_Line);\n    }\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\n\n/** ------------------------------------------------------------\n * archlinuxcn target\n * ------------------------------------------------------------*/\n\ndef_target(os_archlinuxcn, \"archlinuxcn/archcn\");\n\nvoid\nos_archlinuxcn_prelude ()\n{\n  chef_prep_this (os_archlinuxcn, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-05\");\n  chef_set_recipe_last_updated (this, \"2025-09-12\");\n  chef_set_sources_last_updated (this, \"2024-07-03\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 2, \"@ccmywish\", \"@G_I_Y\");\n  chef_set_sauciers (this, 2, \"@happy-game\", \"@Young-Lord\");\n\n  chef_set_os_scope (this);\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note (this,\n    \"可额外使用 chsrc set arch 来更换 Arch Linux 源\",\n    \"You can additionally use chsrc set arch to change Arch Linux source\");\n\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://repo.archlinuxcn.org/\",            DelegateToUpstream},\n  {&Ali,              \"https://mirrors.aliyun.com/archlinuxcn/\",  DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/archlinuxcn/\", DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/archlinuxcn/\", DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/\", DelegateToMirror},\n  {&Sjtug_Zhiyuan,    \"https://mirrors.sjtug.sjtu.edu.cn/archlinux-cn/\", DelegateToMirror},\n  {&Tencent,          \"https://mirrors.cloud.tencent.com/archlinuxcn/\",    DelegateToMirror},\n  // {&Tencent_Intra, \"https://mirrors.cloud.tencentyun.com/archlinuxcn/\", DelegateToMirror},\n\n  /* 不启用原因：过慢 */\n  // {&Netease,          \"https://mirrors.163.com/archlinux-cn/\", DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nos_archlinuxcn_getsrc (char *option)\n{\n  chsrc_view_file (OS_Pacman_MirrorList);\n}\n\n\n/**\n * @consult https://mirrors.tuna.tsinghua.edu.cn/help/archlinuxcn/\n */\nvoid\nos_archlinuxcn_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (os_archlinuxcn);\n\n  chsrc_backup (OS_Pacman_ArchLinuxCN_MirrorList);\n\n  char *arch = chsrc_get_cpuarch ();\n\n  /* 检查是否已存在 archlinuxcn 配置段 */\n  char *check_cmd = \"grep -q '\\\\[archlinuxcn\\\\]' \" OS_Pacman_ArchLinuxCN_MirrorList;\n  int ret = xy_run_get_status (check_cmd);\n\n  if (ret == 0)\n    {\n      char *sed_cmd = xy_strcat (4, \"sed -i '/\\\\[archlinuxcn\\\\]/{n;s|^Server = .*|Server = \",\n                                  source.url, \"$arch|;}' \", OS_Pacman_ArchLinuxCN_MirrorList);\n      chsrc_run (sed_cmd, RunOpt_Default);\n    }\n  else\n    {\n      char *archlinuxcn_config = xy_strcat (3, \"\\n[archlinuxcn]\\nServer = \", source.url, \"$arch\\n\");\n      chsrc_append_to_file (archlinuxcn_config, OS_Pacman_ArchLinuxCN_MirrorList);\n    }\n\n  chsrc_run (\"pacman-key --lsign-key \\\"farseerfc@archlinux.org\\\"\", RunOpt_Dont_Abort_On_Failure); // 此命令可能会失败, 但对换源没有影响\n  chsrc_run (\"pacman -Sy archlinuxcn-keyring\", RunOpt_Default);\n\n  chsrc_run (\"pacman -Syy\", RunOpt_No_Last_New_Line);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/pacman/MSYS2.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_msys2, \"msys2/msys\");\n\nvoid\nos_msys2_prelude ()\n{\n  chef_prep_this (os_msys2, s);\n\n  chef_set_recipe_created_on   (this, \"2023-09-06\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n  chef_set_sources_last_updated (this, \"2025-06-20\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@G_I_Y\");\n  chef_set_sauciers (this, 2, \"@ccmywish\", \"@hezonglun\");\n\n  chef_set_os_scope (this);\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://mirror.msys2.org/\",         DelegateToUpstream},\n  {&Ali,              \"https://mirrors.aliyun.com/msys2\",  DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/msys2\", DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/msys2\", DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/msys2\", DelegateToMirror},\n  {&Tencent,          \"https://mirrors.tencent.com/msys2\", DelegateToMirror},\n  {&Huawei,           \"https://mirrors.huaweicloud.com/msys2\", DelegateToMirror},\n  /* 不启用原因：过慢 */\n  // {&Netease,          \"https://mirrors.163.com/msys2\",  DelegateToMirror},\n  /* 不启用原因：过慢 */\n  // {&Sohu,             \"https://mirrors.sohu.com/msys2\", DelegateToMirror}\n  def_sources_end()\n}\n\n\n/**\n * HELP: 未经测试\n */\nvoid\nos_msys2_setsrc (char *option)\n{\n  chsrc_use_this_source (os_msys2);\n\n  chsrc_backup (\"/etc/pacman.d/mirrorlist.mingw32\");\n  chsrc_backup (\"/etc/pacman.d/mirrorlist.mingw64\");\n  chsrc_backup (\"/etc/pacman.d/mirrorlist.msys\");\n\n  char *prev = xy_strcat (3, \"请针对你的架构下载安装此目录下的文件:\",\n                              source.url,\n                             \"distrib/<架构>/\");\n  chsrc_note2 (prev);\n\n  char *cmd = xy_strcat (3, \"sed -i \\\"s#https\\?://mirror.msys2.org/#\",\n                              source.url,\n                             \"#g\\\" /etc/pacman.d/mirrorlist* \");\n\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/os/pacman/Manjaro-Linux.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(os_manjaro, \"manjaro\");\n\nvoid\nos_manjaro_prelude ()\n{\n  chef_prep_this (os_manjaro, s);\n\n  chef_set_recipe_created_on   (this, \"2023-09-06\");\n  chef_set_recipe_last_updated (this, \"2025-08-10\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@G_I_Y\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_os_scope (this);\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, NULL, DelegateToUpstream}\n  /* Manjaro uses GUI tool, no manual sources needed */\n  def_sources_end()\n}\n\n/**\n * 似乎会弹出GUI，待确定\n */\nvoid\nos_manjaro_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n  char *cmd = \"pacman-mirrors -i -c China -m rank\";\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_run (\"pacman -Syy\", RunOpt_No_Last_New_Line);\n\n  chsrc_conclude (NULL);\n}\n"
  },
  {
    "path": "src/recipe/os/rawstr4c.h",
    "content": "#pragma once\n\n/**\n * Generated by rawstr4c v1.0.0-2025/08/09\n */\n\nchar RAWSTR_os_openSUSE_leap_in_bash[] = \"\\x23\\x20\\xe9\\xa6\\x96\\xe5\\x85\\x88\\xe7\\xa6\\x81\\xe7\\x94\\xa8\\xe5\\xae\\x98\\xe6\\x96\\xb9\\xe8\\xbd\\xaf\\xe4\\xbb\\xb6\\xe6\\xba\\x90\\x0a\\x7a\\x79\\x70\\x70\\x65\\x72\\x20\\x6d\\x72\\x20\\x2d\\x64\\x61\\x0a\\x0a\\x7a\\x79\\x70\\x70\\x65\\x72\\x20\\x61\\x72\\x20\\x2d\\x63\\x66\\x67\\x20\\x27\\x40\\x75\\x72\\x6c\\x40\\x2f\\x64\\x69\\x73\\x74\\x72\\x69\\x62\\x75\\x74\\x69\\x6f\\x6e\\x2f\\x6c\\x65\\x61\\x70\\x2f\\x24\\x72\\x65\\x6c\\x65\\x61\\x73\\x65\\x76\\x65\\x72\\x2f\\x72\\x65\\x70\\x6f\\x2f\\x6f\\x73\\x73\\x2f\\x27\\x20\\x6d\\x69\\x72\\x72\\x6f\\x72\\x2d\\x6f\\x73\\x73\\x0a\\x7a\\x79\\x70\\x70\\x65\\x72\\x20\\x61\\x72\\x20\\x2d\\x63\\x66\\x67\\x20\\x27\\x40\\x75\\x72\\x6c\\x40\\x2f\\x64\\x69\\x73\\x74\\x72\\x69\\x62\\x75\\x74\\x69\\x6f\\x6e\\x2f\\x6c\\x65\\x61\\x70\\x2f\\x24\\x72\\x65\\x6c\\x65\\x61\\x73\\x65\\x76\\x65\\x72\\x2f\\x72\\x65\\x70\\x6f\\x2f\\x6e\\x6f\\x6e\\x2d\\x6f\\x73\\x73\\x2f\\x27\\x20\\x6d\\x69\\x72\\x72\\x6f\\x72\\x2d\\x6e\\x6f\\x6e\\x2d\\x6f\\x73\\x73\\x0a\\x7a\\x79\\x70\\x70\\x65\\x72\\x20\\x61\\x72\\x20\\x2d\\x63\\x66\\x67\\x20\\x27\\x40\\x75\\x72\\x6c\\x40\\x2f\\x75\\x70\\x64\\x61\\x74\\x65\\x2f\\x6c\\x65\\x61\\x70\\x2f\\x24\\x72\\x65\\x6c\\x65\\x61\\x73\\x65\\x76\\x65\\x72\\x2f\\x6f\\x73\\x73\\x2f\\x27\\x20\\x6d\\x69\\x72\\x72\\x6f\\x72\\x2d\\x75\\x70\\x64\\x61\\x74\\x65\\x0a\\x7a\\x79\\x70\\x70\\x65\\x72\\x20\\x61\\x72\\x20\\x2d\\x63\\x66\\x67\\x20\\x27\\x40\\x75\\x72\\x6c\\x40\\x2f\\x75\\x70\\x64\\x61\\x74\\x65\\x2f\\x6c\\x65\\x61\\x70\\x2f\\x24\\x72\\x65\\x6c\\x65\\x61\\x73\\x65\\x76\\x65\\x72\\x2f\\x6e\\x6f\\x6e\\x2d\\x6f\\x73\\x73\\x2f\\x27\\x20\\x6d\\x69\\x72\\x72\\x6f\\x72\\x2d\\x75\\x70\\x64\\x61\\x74\\x65\\x2d\\x6e\\x6f\\x6e\\x2d\\x6f\\x73\\x73\\x0a\\x0a\\x7a\\x79\\x70\\x70\\x65\\x72\\x20\\x61\\x72\\x20\\x2d\\x63\\x66\\x67\\x20\\x27\\x40\\x75\\x72\\x6c\\x40\\x2f\\x75\\x70\\x64\\x61\\x74\\x65\\x2f\\x6c\\x65\\x61\\x70\\x2f\\x24\\x72\\x65\\x6c\\x65\\x61\\x73\\x65\\x76\\x65\\x72\\x2f\\x73\\x6c\\x65\\x2f\\x27\\x20\\x6d\\x69\\x72\\x72\\x6f\\x72\\x2d\\x73\\x6c\\x65\\x2d\\x75\\x70\\x64\\x61\\x74\\x65\\x0a\\x7a\\x79\\x70\\x70\\x65\\x72\\x20\\x61\\x72\\x20\\x2d\\x63\\x66\\x67\\x20\\x27\\x40\\x75\\x72\\x6c\\x40\\x2f\\x75\\x70\\x64\\x61\\x74\\x65\\x2f\\x6c\\x65\\x61\\x70\\x2f\\x24\\x72\\x65\\x6c\\x65\\x61\\x73\\x65\\x76\\x65\\x72\\x2f\\x62\\x61\\x63\\x6b\\x70\\x6f\\x72\\x74\\x73\\x2f\\x27\\x20\\x6d\\x69\\x72\\x72\\x6f\\x72\\x2d\\x62\\x61\\x63\\x6b\\x70\\x6f\\x72\\x74\\x73\\x2d\\x75\\x70\\x64\\x61\\x74\\x65\";\n\nchar RAWSTR_os_openSUSE_tumbleweed_in_bash[] = \"\\x23\\x20\\xe9\\xa6\\x96\\xe5\\x85\\x88\\xe7\\xa6\\x81\\xe7\\x94\\xa8\\xe5\\xae\\x98\\xe6\\x96\\xb9\\xe8\\xbd\\xaf\\xe4\\xbb\\xb6\\xe6\\xba\\x90\\x0a\\x7a\\x79\\x70\\x70\\x65\\x72\\x20\\x6d\\x72\\x20\\x2d\\x64\\x61\\x0a\\x0a\\x7a\\x79\\x70\\x70\\x65\\x72\\x20\\x61\\x72\\x20\\x2d\\x63\\x66\\x67\\x20\\x27\\x40\\x75\\x72\\x6c\\x40\\x2f\\x74\\x75\\x6d\\x62\\x6c\\x65\\x77\\x65\\x65\\x64\\x2f\\x72\\x65\\x70\\x6f\\x2f\\x6f\\x73\\x73\\x2f\\x27\\x20\\x6d\\x69\\x72\\x72\\x6f\\x72\\x2d\\x6f\\x73\\x73\\x0a\\x7a\\x79\\x70\\x70\\x65\\x72\\x20\\x61\\x72\\x20\\x2d\\x63\\x66\\x67\\x20\\x27\\x40\\x75\\x72\\x6c\\x40\\x2f\\x74\\x75\\x6d\\x62\\x6c\\x65\\x77\\x65\\x65\\x64\\x2f\\x72\\x65\\x70\\x6f\\x2f\\x6e\\x6f\\x6e\\x2d\\x6f\\x73\\x73\\x2f\\x27\\x20\\x6d\\x69\\x72\\x72\\x6f\\x72\\x2d\\x6e\\x6f\\x6e\\x2d\\x6f\\x73\\x73\\x0a\\x0a\\x23\\x20\\xe5\\x88\\xb7\\xe6\\x96\\xb0\\xe8\\xbd\\xaf\\xe4\\xbb\\xb6\\xe6\\xba\\x90\\x0a\\x7a\\x79\\x70\\x70\\x65\\x72\\x20\\x72\\x65\\x66\";\n\n"
  },
  {
    "path": "src/recipe/os/rawstr4c.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------------------------------------------------------------\n ! Config Type   : rawstr4c (Markdown)\n ! Config Authors: Aoran Zeng <ccmywish@qq.com>\n ! Contributors  :  Nil Null  <nil@null.org>\n ! Created On    : <2025-07-21>\n ! Last Modified : <2025-08-09>\n ! ---------------------------------------------------------- -->\n\n# rawstr4c input for OS\n\n- prefix = `RAWSTR_os`\n- output = `:global-variable-only-header`\n- translate = `:hex`\n\n## openSUSE\n\n- namespace = `openSUSE`\n\n### Leap\n\n`openSUSE Leap` 换源脚本\n\n```bash\n# 首先禁用官方软件源\nzypper mr -da\n\nzypper ar -cfg '@url@/distribution/leap/$releasever/repo/oss/' mirror-oss\nzypper ar -cfg '@url@/distribution/leap/$releasever/repo/non-oss/' mirror-non-oss\nzypper ar -cfg '@url@/update/leap/$releasever/oss/' mirror-update\nzypper ar -cfg '@url@/update/leap/$releasever/non-oss/' mirror-update-non-oss\n\nzypper ar -cfg '@url@/update/leap/$releasever/sle/' mirror-sle-update\nzypper ar -cfg '@url@/update/leap/$releasever/backports/' mirror-backports-update\n```\n\n### Tumbleweed\n\n`openSUSE Tumbleweed` 换源脚本\n\n```bash\n# 首先禁用官方软件源\nzypper mr -da\n\nzypper ar -cfg '@url@/tumbleweed/repo/oss/' mirror-oss\nzypper ar -cfg '@url@/tumbleweed/repo/non-oss/' mirror-non-oss\n\n# 刷新软件源\nzypper ref\n```\n"
  },
  {
    "path": "src/recipe/recipe-template.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Name     : recipe-template.c\n * File Authors  : 曾奥然 <ccmywish@qq.com>\n * Contributors  : Mikachu2333 <mikachu.23333@zohomail.com>\n *               |\n * Created On    : <2024-08-09>\n * Last Modified : <2026-02-24>\n * -------------------------------------------------------------\n * 本文件作为一个通用模板：\n *\n *    为一个【换源目标(target)】定义具体的【换源方法(recipe)】\n *\n * 模版中:\n * <target>   为该换源目标的名称\n * <category> 为该换源目标的类别，仅有3类: pl,  os, wr\n *            分别对应3个子目录:         lang, os, ware\n * ------------------------------------------------------------*/\n\n\n\n\n/* 模版文件内容从下方第30行正式开始 */\n\n\n\n\n\n/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(<category>_<target>);\n\n/**\n * 定义专服务于该target的镜像站，该例数据为虚拟填充\n */\nstatic MirrorSite_t\nRubyMetric = {\n  IS_DedicatedMirrorSite, /* 镜像站类型 */\n  \"rbmt\",                 /* 该镜像站的 code, 可以这么使用: chsrc set <target> rbmt */\n\n  /* 该镜像站的英文缩写 |   该镜像站的全名    |     镜像站首页  */\n  \"RubyMetric\",           \"RubyMetric 镜像站\",  \"https://rubymetirc.com\",\n\n  /* 是否跳过测速 | 跳过原因(中文) | 跳过原因(英文) */\n  {NotSkip,             NA,                NA,\n  /* 镜像站某个较大的可下载物的下载链接，用于测速 */\n  \"https://rubymetirc.com/target/aws/aws-sdk-go/@v/v1.45.2.zip\",\n  /* 是否为精准测速，若使用间接URL来测速，则填ROUGH */\n   ACCURATE\n  };\n}\n\n\n\nvoid\n<category>_<target>_prelude (void)\n{\n  // op 可以为 NOOP|s|sr|gsr|gs, 代表支持 Get Set Reset 三种操作\n  chef_prep_this (<category>_<target>, op);\n\n  chef_set_recipe_created_on   (this, \"2024-08-09\"); // 文件创建日期\n  chef_set_recipe_last_updated (this, \"2025-08-12\"); // 文件最后一次更新日期\n  chef_set_sources_last_updated (this, \"2025-08-11\"); // 镜像源最后一次更新日期\n\n  chef_set_chef (this, \"@ccmywish\");                  // recipe 负责人\n  chef_set_cooks (this, 2, \"@ccmywish\", \"@nilnull\");  // recipe 核心作者\n  // 做了贡献？将自己的信息加在这里！\n  chef_set_sauciers (this, 2, \"@nulnone\", \"@someone\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_But_NotImplemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  // chef_allow_english(this); // 项目是否支持英文\n  chef_deny_english(this);\n\n  // chef_allow_user_define(this); // 是否支持用户自定义镜像源\n  chef_deny_user_define(this);\n\n  chef_set_note (\"中文备注说明...\", \"English note...\");\n\n  def_sources_begin()\n  {&UpstreamProvider, \"上游默认源链接, 若维护者暂时未知, 可填NULL, 这个主要用于reset\", DelegateToUpstream}\n  {&RubyMetric,       \"https://rubymetirc.com/target\",       DelegateToMirror},\n  {&RubyInstaller,    \"https://rubyinstaller.cn/target\",     DelegateToMirror},\n  {&Gitee,            \"https://gitee.com/RubyMetric/chsrc\",  DelegateToMirror},\n  {&GitHub,           \"https://github.com/RubyMetric/chsrc\", \"https://一个精准测速链接\"}\n  def_sources_end()\n}\n\n\n/**\n * @required 非必需\n *\n * 用于 chsrc get <target>\n */\nvoid\n<category>_<target>_getsrc (char *option)\n{\n  // chsrc get <target>\n}\n\n\n/**\n * @required 必需\n * @consult  写明换源实现的参考地址\n *\n * 用于 chsrc set <target>\n */\nvoid\n<category>_<target>_setsrc (char *option)\n{\n  /* 下面这行是必须的，注入 source 变量 */\n  chsrc_use_this_source (<category>_<target>);\n\n  /* 如果是 target group，你可能想要指定不同的 target 来使用它的源 */\n  // Source_t source = chsrc_yield_source_and_confirm (&pl_js_group_target, option);\n\n  /* 具体的换源步骤，如调用第三方命令... */\n\n  /* 最后总结输出 */\n  chsrc_determine_chgtype (ChgType_xxx);\n  chsrc_conclude (&source);\n}\n\n\n/**\n * @required 非必需\n *\n * 用于 chsrc reset <target>\n */\nvoid\n<category>_<target>_resetsrc (char *option)\n{\n  /* 往往统一在 _setsrc() 中实现，直接调用即可 */\n  // <category>_<target>_setsrc (option);\n}\n\n\n// 最后，请将自己的文件加入到 menu.c 和 chsrc-main.c 对应的位置\n// 形式可以参考其附近的其他食谱\n"
  },
  {
    "path": "src/recipe/ware/Anaconda/Anaconda.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\n#include \"rawstr4c.h\"\n\ndef_target(wr_anaconda, \"conda/anaconda\");\n\nvoid\nwr_anaconda_prelude ()\n{\n  chef_prep_this (wr_anaconda, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-10\");\n  chef_set_recipe_last_updated (this, \"2025-08-09\");\n  chef_set_sources_last_updated (this, \"2025-07-14\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 2, \"@Yangmoooo\", \"@xyx1926885268\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://repo.anaconda.com\", DelegateToUpstream},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn\", DelegateToMirror},\n  {&Bjtu,             \"https://mirror.bjtu.edu.cn\", DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn\", DelegateToMirror},\n  {&Zju,              \"https://mirrors.zju.edu.cn\", DelegateToMirror},\n  {&Pku,              \"https://mirrors.pku.edu.cn\", DelegateToMirror},\n  {&NJTech,           \"https://mirrors.njtech.edu.cn\", DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn\", DelegateToMirror},\n  {&Sjtug_Siyuan,     \"https://mirror.sjtu.edu.cn\", DelegateToMirror},\n  {&Lzuoss,           \"https://mirror.lzu.edu.cn\", DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nwr_anaconda_getsrc (char *option)\n{\n  chsrc_view_file (\"~/.condarc\");\n}\n\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/anaconda/\n */\nvoid\nwr_anaconda_setsrc (char *option)\n{\n  chsrc_use_this_source (wr_anaconda);\n\n  char *w = xy_str_gsub (RAWSTR_wr_anaconda_condarc, \"@1@\", source.url);\n\n  /* Windows 也是在这里 */\n  char *configfile = xy_2strcat (xy_os_home, \"/.condarc\");\n\n  if (xy.on_windows)\n    {\n      if (xy_file_exist (configfile))\n        {\n          chsrc_alert2 (\"配置文件不存在，将使用 conda 命令创建\");\n          bool conda_exist = chsrc_check_program (\"conda\");\n          if (!conda_exist)\n            {\n              chsrc_error (\"未找到 conda 命令，请检查是否存在\");\n              exit (Exit_UserCause);\n            }\n          chsrc_run (\"conda config --set show_channel_urls yes\", RunOpt_Default);\n        }\n    }\n\n  chsrc_note2 (xy_strcat (3, \"请向 \", configfile, \" 中手动添加:\"));\n  println (w);\n\n  chsrc_note2 (\"然后运行 conda clean -i 清除索引缓存，保证用的是镜像站提供的索引\");\n\n  chsrc_note2 (\"若还需要添加其他第三方源, 可参考: https://help.mirrors.cernet.edu.cn/anaconda/\");\n\n  chsrc_determine_chgtype (ChgType_SemiAuto);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/ware/Anaconda/rawstr4c.h",
    "content": "#pragma once\n\n/**\n * Generated by rawstr4c v1.0.0-2025/08/09\n */\n\nchar RAWSTR_wr_anaconda_condarc[] = \"\\143\\150\\141\\156\\156\\145\\154\\163\\072\\012\\040\\040\\055\\040\\144\\145\\146\\141\\165\\154\\164\\163\\012\\163\\150\\157\\167\\137\\143\\150\\141\\156\\156\\145\\154\\137\\165\\162\\154\\163\\072\\040\\164\\162\\165\\145\\012\\144\\145\\146\\141\\165\\154\\164\\137\\143\\150\\141\\156\\156\\145\\154\\163\\072\\012\\040\\040\\055\\040\\100\\061\\100\\057\\141\\156\\141\\143\\157\\156\\144\\141\\057\\160\\153\\147\\163\\057\\155\\141\\151\\156\\012\\040\\040\\055\\040\\100\\061\\100\\057\\141\\156\\141\\143\\157\\156\\144\\141\\057\\160\\153\\147\\163\\057\\162\\012\\040\\040\\055\\040\\100\\061\\100\\057\\141\\156\\141\\143\\157\\156\\144\\141\\057\\160\\153\\147\\163\\057\\155\\163\\171\\163\\062\\012\\143\\165\\163\\164\\157\\155\\137\\143\\150\\141\\156\\156\\145\\154\\163\\072\\012\\040\\040\\143\\157\\156\\144\\141\\055\\146\\157\\162\\147\\145\\072\\040\\100\\061\\100\\057\\141\\156\\141\\143\\157\\156\\144\\141\\057\\143\\154\\157\\165\\144\\012\\040\\040\\160\\171\\164\\157\\162\\143\\150\\072\\040\\100\\061\\100\\057\\141\\156\\141\\143\\157\\156\\144\\141\\057\\143\\154\\157\\165\\144\";\n\n"
  },
  {
    "path": "src/recipe/ware/Anaconda/rawstr4c.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------------------------------------------------------------\n ! Config Type   : rawstr4c (Markdown)\n ! Config Authors: Aoran Zeng <ccmywish@qq.com>\n ! Contributors  :  Nil Null  <nil@null.org>\n ! Created On    : <2025-07-14>\n ! Last Modified : <2025-08-08>\n ! ---------------------------------------------------------- -->\n\n# rawstr4c input\n\n- output = `:global-variable-only-header`\n- translate = `:oct`\n\n## Anaconda\n\n- prefix = `RAWSTR_wr_anaconda`\n- no-postfix = `true`\n- name = `condarc`\n\n```yaml\nchannels:\n  - defaults\nshow_channel_urls: true\ndefault_channels:\n  - @1@/anaconda/pkgs/main\n  - @1@/anaconda/pkgs/r\n  - @1@/anaconda/pkgs/msys2\ncustom_channels:\n  conda-forge: @1@/anaconda/cloud\n  pytorch: @1@/anaconda/cloud\n```\n"
  },
  {
    "path": "src/recipe/ware/CocoaPods.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(wr_cocoapods, \"cocoa/cocoapods/cocoapod\");\n\nvoid\nwr_cocoapods_prelude ()\n{\n  chef_prep_this (wr_cocoapods, s);\n\n  chef_set_recipe_created_on   (this, \"2024-06-08\");\n  chef_set_recipe_last_updated (this, \"2025-08-09\");\n  chef_set_sources_last_updated (this, \"2025-07-13\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://github.com/CocoaPods/Specs.git\", DelegateToUpstream},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/git/CocoaPods/Specs.git\", DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn/git/CocoaPods/Specs.git\", DelegateToMirror},\n  {&Nyist,            \"https://mirror.nyist.edu.cn/git/CocoaPods/Specs.git\", DelegateToMirror}\n  def_sources_end()\n}\n\n\n/**\n * @consult https://mirrors.tuna.tsinghua.edu.cn/help/CocoaPods/\n */\nvoid\nwr_cocoapods_setsrc (char *option)\n{\n  chsrc_use_this_source (wr_cocoapods);\n\n  chsrc_note2 (\"请手动执行以下命令:\");\n  p(\"cd ~/.cocoapods/repos\");\n  p(\"pod repo remove master\");\n  char *git_cmd = xy_strcat (3, \"git clone \", source.url, \" master\");\n  p(git_cmd);\n  br();\n\n  chsrc_note2 (\"最后进入项目工程目录，在Podfile中第一行加入:\");\n  char *source_str = xy_strcat (3, \"source '\", source.url, \"'\");\n  p(source_str);\n\n  chsrc_determine_chgtype (ChgType_Manual);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/ware/Docker/Docker.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\n#include \"rawstr4c.h\"\n\nstatic MirrorSite_t DaoCloud =\n{\n  IS_DedicatedMirrorSite,\n  \"daocloud\", \"DaoCloud\",\"上海道客网络科技有限公司\", \"https://www.daocloud.io/\",\n  // 没有找到 DaoCloud 合适的下载链接，先随便给一个，以规避 chsrc 自动测速时所有 Docker Hub 镜像站都没有测速链接带来的 Bug\n  {NotSkip, NA, NA, \"https://qiniu-download-public.daocloud.io/DaoCloud_Enterprise/dce5/offline-community-v0.18.0-amd64.tar\", ACCURATE}\n},\n\nFit2Cloud =\n{\n  IS_DedicatedMirrorSite,\n  \"fit2cloud\", \"FIT2CLOUD\", \"杭州飞致云信息科技有限公司\", \"https://www.fit2cloud.com/\",\n  {SKIP, ToFill, ToFill, NULL, ROUGH}\n};\n\ndef_target(wr_docker, \"docker/dockerhub\");\n\nvoid\nwr_docker_prelude ()\n{\n  chef_prep_this (wr_docker, gs);\n\n  chef_set_recipe_created_on   (this, \"2024-06-08\");\n  chef_set_recipe_last_updated (this, \"2025-08-09\");\n  chef_set_sources_last_updated (this, \"2025-07-14\");\n\n  chef_set_chef (this, \"@happy-game\");\n  chef_set_cooks (this, 2, \"@happy-game\", \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://hub.docker.com/\", DelegateToUpstream},\n  {&DaoCloud,         \"https://docker.m.daocloud.io\", DelegateToMirror},\n  {&Fit2Cloud,        \"https://docker.1panel.live\", DelegateToMirror}\n  def_sources_end()\n}\n\n#define WR_Docker_ConfigFile \"/etc/docker/daemon.json\"\n\nvoid\nwr_docker_getsrc (char *option)\n{\n  if (xy.on_linux || xy.on_bsd)\n    {\n      chsrc_view_file (WR_Docker_ConfigFile);\n    }\n  else\n    {\n      chsrc_note2 (\"请打开 Docker Desktop 设置\");\n      chsrc_note2 (\"选择 'Docker Engine' 选项卡，在该选项卡中找到 'registry-mirrors' 一栏查看\");\n    }\n}\n\n/**\n * @consult\n *  1. https://mirrors.ustc.edu.cn/help/dockerhub.html\n *  2. https://www.cnblogs.com/yuzhihui/p/17461781.html\n */\nvoid\nwr_docker_setsrc (char *option)\n{\n  chsrc_ensure_root ();\n\n  chsrc_use_this_source (wr_docker);\n\n  if (xy.on_linux || xy.on_bsd)\n    {\n      char *to_add = xy_str_gsub (RAWSTR_wr_docker_insert_content, \"@1@\", source.url);\n\n      if (chsrc_check_file (WR_Docker_ConfigFile))\n        {\n          chsrc_note2 (\"已找到Docker配置文件，将自动换源\");\n          chsrc_backup (WR_Docker_ConfigFile);\n\n          if (chsrc_check_program_quietly (\"jq\"))\n            {\n              /* 检查是否已经存在 source.url */\n              char *cmd = xy_str_gsub (RAWSTR_wr_docker_check_cmd, \"@1@\", source.url);\n                    cmd = xy_str_gsub (cmd, \"@2@\", WR_Docker_ConfigFile);\n\n              char *result = xy_run (cmd, 0);\n              if (result && !xy_streql (result, \"null\"))\n                {\n                  chsrc_alert2 (\"已存在源，无需重复添加\");\n                }\n              else\n                {\n                  cmd = xy_str_gsub (RAWSTR_wr_docker_insert_cmd, \"@1@\", source.url);\n                  cmd = xy_str_gsub (cmd, \"@2@\", WR_Docker_ConfigFile);\n                  chsrc_run (cmd, RunOpt_Default);\n                  chsrc_succ2 (\"源已添加\");\n                }\n            }\n          else\n            {\n              chsrc_alert2 (\"未找到 jq 命令, 将使用 sed 换源\");\n              char *cmd = xy_str_gsub (RAWSTR_wr_docker_sed_command, \"@1@\", source.url);\n                    cmd = xy_str_gsub (cmd, \"@2@\", WR_Docker_ConfigFile);\n              chsrc_run (cmd, RunOpt_Default);\n            }\n        }\n      else\n        {\n          /* 不存在 /etc/docker/daemon.json 时可以直接写入文件 */\n          chsrc_alert2 (\"未找到Docker配置文件, 将自动创建\");\n          chsrc_ensure_dir (\"/etc/docker\");\n          chsrc_run ( xy_2strcat (\"touch \", WR_Docker_ConfigFile), RunOpt_Default);\n\n          chsrc_append_to_file (to_add, WR_Docker_ConfigFile);\n        }\n\n      if (xy.on_linux)\n        {\n          /* 由于 systemctl restart docker 会导致所有容器停止，所以不自动重启 */\n          chsrc_alert2 (\"请自行运行: sudo systemctl restart docker\");\n          chsrc_alert2 (\"该命令会重启所有容器, 请在合适的时机执行\");\n        }\n      else\n        {\n          chsrc_alert2 (\"然后请手动重启 docker 服务\");\n        }\n    }\n  else\n    {\n      chsrc_note2 (\"请打开 Docker Desktop 设置\");\n      chsrc_note2 (\"选择 'Docker Engine' 选项卡，在该选项卡中找到 'registry-mirrors' 一栏，添加镜像地址:\");\n      println (source.url);\n    }\n\n  chsrc_determine_chgtype (ChgType_SemiAuto);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/ware/Docker/README.md",
    "content": "# Docker\n\n- USTC 与 SJTUG 于 2024-06-06 停止支持 DockerHub\n- NJU 于 2024-06-07 停止支持 DockerHub\n"
  },
  {
    "path": "src/recipe/ware/Docker/rawstr4c.h",
    "content": "#pragma once\n\n/**\n * Generated by rawstr4c v1.0.0-2025/08/09\n */\n\nchar RAWSTR_wr_docker_insert_content[] = \"\\x7b\\x0a\\x20\\x20\\x22\\x72\\x65\\x67\\x69\\x73\\x74\\x72\\x79\\x2d\\x6d\\x69\\x72\\x72\\x6f\\x72\\x73\\x22\\x3a\\x20\\x5b\\x22\\x40\\x31\\x40\\x22\\x5d\\x0a\\x7d\";\n\nchar RAWSTR_wr_docker_check_cmd[] = \"\\x6a\\x71\\x20\\x27\\x2e\\x5b\\x22\\x72\\x65\\x67\\x69\\x73\\x74\\x72\\x79\\x2d\\x6d\\x69\\x72\\x72\\x6f\\x72\\x73\\x22\\x5d\\x20\\x7c\\x20\\x69\\x6e\\x64\\x65\\x78\\x28\\x22\\x40\\x31\\x40\\x22\\x29\\x27\\x20\\x40\\x32\\x40\";\n\nchar RAWSTR_wr_docker_insert_cmd[] = \"\\x6a\\x71\\x20\\x27\\x2e\\x5b\\x22\\x72\\x65\\x67\\x69\\x73\\x74\\x72\\x79\\x2d\\x6d\\x69\\x72\\x72\\x6f\\x72\\x73\\x22\\x5d\\x20\\x7c\\x3d\\x20\\x5b\\x22\\x40\\x31\\x40\\x22\\x5d\\x20\\x2b\\x20\\x2e\\x27\\x20\\x40\\x32\\x40\\x2e\\x62\\x61\\x6b\\x20\\x3e\\x20\\x20\\x40\\x32\\x40\";\n\nchar RAWSTR_wr_docker_sed_command[] = \"\\x73\\x65\\x64\\x20\\x2d\\x7a\\x20\\x2d\\x69\\x20\\x27\\x73\\x2f\\x22\\x72\\x65\\x67\\x69\\x73\\x74\\x72\\x79\\x2d\\x6d\\x69\\x72\\x72\\x6f\\x72\\x73\\x22\\x3a\\x5b\\x5e\\x5d\\x5d\\x2a\\x5d\\x2f\\x22\\x72\\x65\\x67\\x69\\x73\\x74\\x72\\x79\\x2d\\x6d\\x69\\x72\\x72\\x6f\\x72\\x73\\x22\\x3a\\x5b\\x22\\x40\\x31\\x40\\x22\\x5d\\x2f\\x27\\x20\\x40\\x32\\x40\";\n\n"
  },
  {
    "path": "src/recipe/ware/Docker/rawstr4c.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------------------------------------------------------------\n ! Config Type   : rawstr4c (Markdown)\n ! Config Authors: Aoran Zeng <ccmywish@qq.com>\n !               | happy game <happygame1024@gmail.com>\n ! Contributors  :  Nil Null  <nil@null.org>\n ! Created On    : <2025-07-14>\n ! Last Modified : <2025-08-10>\n ! ---------------------------------------------------------- -->\n\n# rawstr4c input\n\n- prefix = `RAWSTR_wr_docker`\n- output = `:global-variable-only-header`\n- translate = `:hex`\n- no-postfix = `true`\n\n\n\n## auto insert content\n\n- name = `insert_content`\n\n```json\n{\n  \"registry-mirrors\": [\"@1@\"]\n}\n```\n\n\n\n## jq command1\n\n检查配置文件中是否已存在即将要换的源\n\n- name = `check_cmd`\n\n```sh\njq '.[\"registry-mirrors\"] | index(\"@1@\")' @2@\n```\n\n\n\n## jq command2\n\n插入新的源到配置文件中\n\n- name = `insert_cmd`\n\n```sh\njq '.[\"registry-mirrors\"] |= [\"@1@\"] + .' @2@.bak >  @2@\n```\n\n注释: `|=` 为赋值, `+ .` 表示把原数组加过来\n\n\n\n## sed command\n\n没有 `jq` 时，用 `sed` 换源，写入到配置文件中\n\n```sh\nsed -z -i 's/\"registry-mirrors\":[^]]*]/\"registry-mirrors\":[\"@1@\"]/' @2@\n```\n\n注释: `[^]]*` 即不是 `]` 的所有字符, 后面再跟一个 `]` 由于没有前面的 `[`，因此可被解析为普通字符 `]`，没有特殊含义\n"
  },
  {
    "path": "src/recipe/ware/Emacs.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\nstatic MirrorSite_t EmacsChina =\n{\n  IS_DedicatedMirrorSite,\n  \"emacschina\", \"EmacsChina\", \"Emacs China 社区\", \"https://elpamirror.emacs-china.org/\",\n  {SKIP, ToFill, ToFill, NULL, ROUGH}\n};\n\ndef_target(wr_emacs, \"emacs/elpa\");\n\nvoid\nwr_emacs_prelude ()\n{\n  chef_prep_this (wr_emacs, s);\n\n  chef_set_recipe_created_on   (this, \"2023-10-10\");\n  chef_set_recipe_last_updated (this, \"2025-08-09\");\n  chef_set_sources_last_updated (this, \"2025-07-13\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note (this, \"Emacs用户往往只需要一次性换源，只会极少次调用 chsrc，我们只给用户提供文档\",\n                       \"Emacs users typically only need to switch sources once and rarely call chsrc, so we only provide documentation to users\");\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://elpa.gnu.org/\", DelegateToUpstream},\n  {&MirrorZ,          \"https://help.mirrors.cernet.edu.cn/elpa/\", DelegateToMirror},\n  {&Sjtug_Zhiyuan,    \"https://mirrors.sjtug.sjtu.edu.cn/docs/emacs-elpa\", DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/help/elpa/\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/help/elpa/\", DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/help/elpa.html\", DelegateToMirror},\n  {&Zju,              \"https://mirrors.zju.edu.cn/docs/elpa/\", DelegateToMirror},\n  {&EmacsChina,       \"https://elpamirror.emacs-china.org/\", DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nwr_emacs_setsrc (char *option)\n{\n  chsrc_use_this_source (wr_emacs);\n\n  chsrc_note2 (\"Emacs换源涉及Elisp, 需要手动查阅并换源:\");\n  p (source.url);\n\n  chsrc_determine_chgtype (ChgType_Manual);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/ware/Flatpak.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(wr_flatpak, \"flatpak/flathub\");\n\nvoid\nwr_flatpak_prelude ()\n{\n  chef_prep_this (wr_flatpak, gsr);\n\n  chef_set_recipe_created_on   (this, \"2023-09-11\");\n  chef_set_recipe_last_updated (this, \"2025-08-09\");\n  chef_set_sources_last_updated (this, \"2025-05-27\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@jialinlvcn\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  chef_set_note (this, \"对Flathub目标进行测速的文件非常小，测速效果严重失真，若你知道可供测速的URL，欢迎参与贡献: chsrc issue\",\n                       \"The test file for Flathub is very small, causing inaccurate speed test results. If you know a URL suitable for speed testing, welcome to contribute: chsrc issue\");\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://flathub.org/repo\",                  DelegateToUpstream},\n  {&Sjtug_Siyuan,     \"https://mirror.sjtu.edu.cn/flathub\",        DelegateToMirror},\n  {&Sjtug_Zhiyuan,    \"https://mirrors.sjtug.sjtu.edu.cn/flathub\", DelegateToMirror},\n  def_sources_end()\n\n\n  chef_set_provider_smURL (&UpstreamProvider, \"https://flathub.org/repo/flathub.gpg\");\n  /* upstream 默认是 ACCURATE 的，但是我们给了一个超小的文件，测速效果严重失真，所以改为 ROUGH */\n  chef_set_provider_sm_accuracy (&UpstreamProvider, ROUGH);\n\n  /**\n   * @note 下述上海交大两个镜像站都可使用，但实际使用时出现过无法访问的情况 (GitHub-#178)，\n   *       所以额外定义两个镜像站以更改测速链接为一个很小的文件: flathub.gpg\n   *       若无速度，则证明无法访问。\n   *       注意，这会使得测速的效果严重失真。\n   */\n  chef_set_provider_smURL (&Sjtug_Siyuan,  \"https://mirror.sjtu.edu.cn/flathub/flathub.gpg\");\n  chef_set_provider_smURL (&Sjtug_Zhiyuan, \"https://mirrors.sjtug.sjtu.edu.cn/flathub/flathub.gpg\");\n  /* 由于实在找不到其他可测文件，所以这也只能是 ROUGH */\n  chef_set_provider_sm_accuracy (&Sjtug_Siyuan, ROUGH);\n  chef_set_provider_sm_accuracy (&Sjtug_Zhiyuan, ROUGH);\n}\n\n\nvoid\nwr_flatpak_getsrc (char *option)\n{\n  chsrc_run (\"flatpak remotes\", RunOpt_Default);\n  chsrc_run (\"flatpak remote-info flathub\", RunOpt_Default);\n}\n\n\n/**\n * @consult https://mirrors.sjtug.sjtu.edu.cn/docs/flathub\n */\nvoid\nwr_flatpak_setsrc (char *option)\n{\n  chsrc_use_this_source (wr_flatpak);\n\n  chsrc_alert2 (\"若出现问题，可先调用以下命令:\");\n  char *note = xy_strcat (3,\n    \"wget \", source.url, \"/flathub.gpg\\n\"\n    \"flatpak remote-modify --gpg-import=flathub.gpg flathub\"\n  );\n  say (note);\n\n  char *repo_note = \"Flathub 中部分软件由于重分发授权问题，需要从官方服务器下载，无法使用镜像站加速\\n\"\n    \"比如 NVIDIA 驱动、JetBrains 系列软件等\\n\"\n    \"尝试运行 flatpak remote-modify flathub --url=https://flathub.org/repo\";\n  say (repo_note);\n\n  char *cmd = xy_2strcat (\"flatpak remote-modify flathub --url=\", source.url);\n  chsrc_run (cmd, RunOpt_Default);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nwr_flatpak_resetsrc (char *option)\n{\n  wr_flatpak_setsrc (option);\n}\n"
  },
  {
    "path": "src/recipe/ware/Guix.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(wr_guix, \"guix\");\n\nvoid\nwr_guix_prelude ()\n{\n  chef_prep_this (wr_guix, s);\n\n  chef_set_recipe_created_on   (this, \"2023-09-11\");\n  chef_set_recipe_last_updated (this, \"2025-08-09\");\n  chef_set_sources_last_updated (this, \"2025-07-13\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note (this, \"目前只有一个源, guixcn 的源不知道是否可用\",\n                       \"Currently only one source available, guixcn source availability unknown\");\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://git.savannah.gnu.org/git/guix.git\", DelegateToUpstream},\n  {&Sjtug_Zhiyuan,    \"https://mirror.sjtu.edu.cn/git/guix.git\", DelegateToMirror}\n  def_sources_end()\n}\n\n\n/**\n * @consult https://mirrors.sjtug.sjtu.edu.cn/docs/guix\n */\nvoid\nwr_guix_setsrc (char *option)\n{\n  chsrc_use_this_source (wr_guix);\n\n  char *file =  xy_strcat (3, \"(list (channel\\n\"\n                               \"       (inherit (car %default-channels))\\n\"\n                               \"       (url \\\"\", source.url, \"\\\")))\");\n\n  chsrc_note2 (\"为防止扰乱配置文件，请手动写入以下内容到 ~/.config/guix/channels.scm 文件中\");\n  p(file);\n\n  chsrc_determine_chgtype (ChgType_Manual);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/ware/Homebrew/Homebrew.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\n#include \"rawstr4c.h\"\n\ndef_target(wr_homebrew, \"brew/homebrew\");\n\nvoid\nwr_homebrew_prelude ()\n{\n  chef_prep_this (wr_homebrew, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-10\");\n  chef_set_recipe_last_updated (this, \"2025-09-12\");\n  chef_set_sources_last_updated (this, \"2025-07-13\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@Word2VecT\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_allow_english(this);\n  chef_deny_user_define(this);\n\n  chef_set_note (this, \"该换源通过写入环境变量实现，若多次换源，请手动清理profile文件\",\n                       \"This source switching is implemented by writing environment variables. If switching sources multiple times, please manually clean the profile file\");\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://github.com/Homebrew/brew.git\", DelegateToUpstream},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/\", DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn/\", DelegateToMirror},\n  {&Nyist,            \"https://mirror.nyist.edu.cn/\", DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nwr_homebrew_getsrc (char *option)\n{\n  int status = xy_run_get_status (RAWSTR_wr_homebrew_read_config_cmd);\n  if (status != 0) { xy_noop(); }\n}\n\n/**\n * @consult https://mirrors.tuna.tsinghua.edu.cn/help/homebrew/\n *\n * 自brew 4.0.0 (2023 年 2 月 16日) 起，\n * HOMEBREW_INSTALL_FROM_API 会成为默认行为，无需设置。大部分用户无需再克隆 homebrew-core 仓库，故无需设置 HOMEBREW_CORE_GIT_REMOTE 环境变量；\n * 但是为了以防万一，我们还是为用户设置该环境变量\n */\nvoid\nwr_homebrew_setsrc (char *option)\n{\n  chsrc_use_this_source (wr_homebrew);\n\n  char *w = xy_str_gsub (RAWSTR_wr_homebrew_config_in_bash, \"@1@\", source.url);\n\n  char *zshrc = xy_zshrc;\n  chsrc_backup (zshrc);\n  chsrc_append_to_file (w, zshrc);\n\n  char *bashrc = xy_bashrc;\n  if (xy_file_exist (bashrc))\n    {\n      chsrc_backup (bashrc);\n      chsrc_append_to_file (w, bashrc);\n    }\n\n  char *fishrc = xy_fishrc;\n  if (xy_file_exist (fishrc))\n    {\n      char *w = xy_str_gsub (RAWSTR_wr_homebrew_config_in_fish, \"@1@\", source.url);\n      chsrc_backup (fishrc);\n      chsrc_append_to_file (w, fishrc);\n    }\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n  chsrc_alert2 (\"请重启终端使Homebrew环境变量生效\");\n}\n"
  },
  {
    "path": "src/recipe/ware/Homebrew/rawstr4c.h",
    "content": "#pragma once\n\n/**\n * Generated by rawstr4c v1.0.0-2025/08/09\n */\n\nchar RAWSTR_wr_homebrew_read_config_cmd[] = \"echo HOMEBREW_API_DOMAIN=$HOMEBREW_API_DOMAIN;\\necho HOMEBREW_BOTTLE_DOMAIN=$HOMEBREW_BOTTLE_DOMAIN;\\necho HOMEBREW_BREW_GIT_REMOTE=$HOMEBREW_BREW_GIT_REMOTE;\\necho HOMEBREW_CORE_GIT_REMOTE=$HOMEBREW_CORE_GIT_REMOTE;\";\n\nchar RAWSTR_wr_homebrew_config_in_bash[] = \"# ------ chsrc BLOCK BEGIN for Homebrew ------\\nexport HOMEBREW_BREW_GIT_REMOTE=\\\"@1@/git/homebrew/brew.git\\\"\\nexport HOMEBREW_CORE_GIT_REMOTE=\\\"@1@/git/homebrew/homebrew-core.git\\\"\\n# For Bottles\\nexport HOMEBREW_API_DOMAIN=\\\"@1@/homebrew-bottles/api\\\"\\nexport HOMEBREW_BOTTLE_DOMAIN=\\\"@1@/homebrew-bottles\\\"\\n# ------ chsrc BLOCK ENDIN for Homebrew ------\";\n\nchar RAWSTR_wr_homebrew_config_in_fish[] = \"# ------ chsrc BLOCK BEGIN for Homebrew ------\\nset -x HOMEBREW_BREW_GIT_REMOTE \\\"@1@/git/homebrew/brew.git\\\"\\nset -x HOMEBREW_CORE_GIT_REMOTE \\\"@1@/git/homebrew/homebrew-core.git\\\"\\n# For Bottles\\nset -x HOMEBREW_API_DOMAIN    \\\"@1@/homebrew-bottles/api\\\"\\nset -x HOMEBREW_BOTTLE_DOMAIN \\\"@1@/homebrew-bottles\\\"\\n# ------ chsrc BLOCK ENDIN for Homebrew ------\";\n\n"
  },
  {
    "path": "src/recipe/ware/Homebrew/rawstr4c.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------------------------------------------------------------\n ! Config Type   : rawstr4c (Markdown)\n ! Config Authors: Aoran Zeng <ccmywish@qq.com>\n ! Contributors  :  Word2VecT <tangzinan@bupt.edu.cn>\n ! Created On    : <2025-07-14>\n ! Last Modified : <2025-08-08>\n ! ---------------------------------------------------------- -->\n\n# rawstr4c input\n\n该文件尽可能测试 `rawstr4c` 的多个功能，以下三个变量的输出，将分别为:\n\n1. `RAWSTR_wr_homebrew_read_config_cmd`\n2. `RAWSTR_wr_homebrew_config_in_bash`\n3. `RAWSTR_wr_homebrew_config_in_fish`\n\n若不同，则生成有问题。\n\n- prefix = `RAWSTR_wr_homebrew`\n- postfix = `:use-language`\n\n- translate = `:escape`\n- output = `:global-variable-only-header`\n\n## Homebrew\n\n### read user env\n\n下面的命令对于 `Bash`、`Zsh` 和 `Fish` 都适用\n\n- name = `RAWSTR_wr_homebrew_read_config_cmd`\n- name-literally = `true`\n\n测试一下 name-literally 功能\n\n```bash\necho HOMEBREW_API_DOMAIN=$HOMEBREW_API_DOMAIN;\necho HOMEBREW_BOTTLE_DOMAIN=$HOMEBREW_BOTTLE_DOMAIN;\necho HOMEBREW_BREW_GIT_REMOTE=$HOMEBREW_BREW_GIT_REMOTE;\necho HOMEBREW_CORE_GIT_REMOTE=$HOMEBREW_CORE_GIT_REMOTE;\n```\n\n### Bash config\n\n- no-prefix = `false`\n- no-postfix = `true`\n- name = `config_in_bash`\n\n测试一下 no-postfix 功能\n\n```bash\n# ------ chsrc BLOCK BEGIN for Homebrew ------\nexport HOMEBREW_BREW_GIT_REMOTE=\"@1@/git/homebrew/brew.git\"\nexport HOMEBREW_CORE_GIT_REMOTE=\"@1@/git/homebrew/homebrew-core.git\"\n# For Bottles\nexport HOMEBREW_API_DOMAIN=\"@1@/homebrew-bottles/api\"\nexport HOMEBREW_BOTTLE_DOMAIN=\"@1@/homebrew-bottles\"\n# ------ chsrc BLOCK ENDIN for Homebrew ------\n```\n\n### Fish config\n\n- name = `config`\n- language = `fish`\n\n`Fish` 没有高亮，所以我们这里的 code block 用 `bash` 指示 ，我们刚好测试一下 language 功能\n\n```bash\n# ------ chsrc BLOCK BEGIN for Homebrew ------\nset -x HOMEBREW_BREW_GIT_REMOTE \"@1@/git/homebrew/brew.git\"\nset -x HOMEBREW_CORE_GIT_REMOTE \"@1@/git/homebrew/homebrew-core.git\"\n# For Bottles\nset -x HOMEBREW_API_DOMAIN    \"@1@/homebrew-bottles/api\"\nset -x HOMEBREW_BOTTLE_DOMAIN \"@1@/homebrew-bottles\"\n# ------ chsrc BLOCK ENDIN for Homebrew ------\n```\n"
  },
  {
    "path": "src/recipe/ware/Nix.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(wr_nix, \"nix\");\n\n/**\n * 运行时检查到底是哪种安装方式\n *\n * https://github.com/RubyMetric/chsrc/issues/337\n */\nbool\nwr_nix_is_multi_user_installation_mode ()\n{\n  if (xy_file_exist (\"/nix/var/nix/daemon-socket/socket\"))\n    {\n     return true;\n    }\n  else\n    {\n      return false;\n    }\n}\n\nvoid\nwr_nix_prelude ()\n{\n  chef_prep_this (wr_nix, s);\n\n  chef_set_recipe_created_on   (this, \"2023-09-26\");\n  chef_set_recipe_last_updated (this, \"2026-02-24\");\n  chef_set_sources_last_updated (this, \"2025-07-13\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 0);\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Able_And_Implemented);\n\n  if (wr_nix_is_multi_user_installation_mode ())\n    {\n      chef_set_default_scope (this, SystemScope);\n    }\n  else\n    {\n      chef_set_default_scope (this, UserScope);\n    }\n\n  chef_deny_english(this);\n  chef_deny_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://channels.nixos.org/\", DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/nix-channels/\", DelegateToMirror},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/nix-channels/\", DelegateToMirror},\n  {&Nju,              \"https://mirror.nju.edu.cn/nix-channels/\", DelegateToMirror},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/nix-channels/\", DelegateToMirror},\n  {&Sjtug_Siyuan,     \"https://mirror.sjtu.edu.cn/nix-channels/\", DelegateToMirror},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/nix-channels/\", DelegateToMirror},\n  {&Iscas,            \"https://mirror.iscas.ac.cn/nix-channels/\", DelegateToMirror}\n  def_sources_end()\n}\n\n\nvoid\nwr_nix_check_cmd ()\n{\n  chsrc_ensure_program (\"nix-channel\");\n}\n\n/**\n * @consult\n *    1. https://help.mirrors.cernet.edu.cn/nix-channels/\n *    2. https://gitee.com/RubyMetric/chsrc/issues/I83894\n *    3. https://github.com/RubyMetric/chsrc/issues/337\n */\nvoid\nwr_nix_setsrc (char *option)\n{\n  wr_nix_check_cmd ();\n\n  chsrc_use_this_source (wr_nix);\n\n  char *user_scope_nix_config = \"~/.config/nix/nix.conf\";\n  char *system_scope_nix_config = \"/etc/nix/nix.conf\";\n\n  char *config_file = NULL;\n\n  if (wr_nix_is_multi_user_installation_mode ())\n    {\n      config_file = system_scope_nix_config;\n    }\n  else\n    {\n      config_file = user_scope_nix_config;\n    }\n\n  char *cmd = xy_strcat (3, \"nix-channel --add \", source.url, \"nixpkgs-unstable nixpkgs\");\n  chsrc_run (cmd, RunOpt_Default);\n\n  char *w = xy_strcat (3, \"substituters = \", source.url, \"store https://cache.nixos.org/\");\n  chsrc_append_to_file (w, config_file);\n\n  chsrc_run (\"nix-channel --update\", RunOpt_Default);\n\n  chsrc_note2 (\"若你使用的是NixOS，请确认你的系统版本<version>（如22.11），并手动运行:\");\n  cmd = xy_strcat (3, \"nix-channel --add \", source.url, \"nixpkgs-<version> nixpkgs\");\n  p(cmd);\n\n  cmd = xy_strcat (3, \"nix.settings.substituters = [ \\\"\", source.url, \"store\\\" ];\");\n  chsrc_note2 (\"若你使用的是NixOS，请额外添加下述内容至 configuration.nix 中\");\n  p(cmd);\n\n  chsrc_determine_chgtype (ChgType_SemiAuto);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/ware/TeX-Live.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * MiKTeX 和 TeX Live 都是流行的 LaTeX 发行版，但它们是不同的实现\n * ------------------------------------------------------------*/\n\ndef_target(wr_tex, \"latex/ctan/tex/texlive/miktex/tlmgr/mpm\");\n\nvoid\nwr_tex_prelude ()\n{\n  chef_prep_this (wr_tex, gs);\n\n  chef_set_recipe_created_on   (this, \"2023-09-10\");\n  chef_set_recipe_last_updated (this, \"2025-08-09\");\n  chef_set_sources_last_updated (this, \"2025-07-28\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@Mikachu2333\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://ctan.org/tex-archive/systems/texlive/tlnet\", DelegateToUpstream},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/CTAN/systems/texlive/tlnet\", DelegateToMirror},\n  {&Sjtug_Zhiyuan,    \"https://mirrors.sjtug.sjtu.edu.cn/ctan/systems/texlive/tlnet\",\n                      \"https://mirrors.sustech.edu.cn/CTAN/systems/texlive/tlnet/archive/fandol.tar.xz\"},\n  {&Tuna,             \"https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/tlnet\",\n                      \"https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/tlnet/archive/fandol.tar.xz\"},\n  {&Bfsu,             \"https://mirrors.bfsu.edu.cn/CTAN/systems/texlive/tlnet\",\n                      \"https://mirrors.bfsu.edu.cn/CTAN/systems/texlive/tlnet/archive/fandol.tar.xz\"},\n  {&Bjtu,             \"https://mirror.bjtu.edu.cn/ctan/systems/texlive/tlnet\",\n                      \"https://mirror.bjtu.edu.cn/ctan/systems/texlive/tlnet/archive/fandol.tar.xz\"},\n  {&Lzuoss,           \"https://mirror.lzu.edu.cn/CTAN/systems/texlive/tlnet\",\n                      \"https://mirror.lzu.edu.cn/CTAN/systems/texlive/tlnet/archive/fandol.tar.xz\"},\n  {&Jlu,              \"https://mirrors.jlu.edu.cn/CTAN/systems/texlive/tlnet\",\n                      \"https://mirrors.jlu.edu.cn/CTAN/systems/texlive/tlnet/archive/fandol.tar.xz\"},\n  {&Sustech,          \"https://mirrors.sustech.edu.cn/CTAN/systems/texlive/tlnet\",\n                      \"https://mirrors.sustech.edu.cn/CTAN/systems/texlive/tlnet/archive/fandol.tar.xz\"}\n  def_sources_end()\n}\n\n\nvoid\nwr_tex_check_cmd (bool *tlmgr_exist, bool *mpm_exist)\n{\n  *tlmgr_exist = chsrc_check_program (\"tlmgr\");\n  *mpm_exist = chsrc_check_program (\"mpm\");\n\n  if (!*tlmgr_exist && !*mpm_exist)\n    {\n      chsrc_error (\"未找到 tlmgr 或 mpm 命令，请检查是否存在（其一）\");\n      exit (Exit_UserCause);\n    }\n}\n\nvoid\nwr_tex_getsrc (char *option)\n{\n  bool tlmgr_exist, mpm_exist;\n  wr_tex_check_cmd (&tlmgr_exist, &mpm_exist);\n\n  if (tlmgr_exist)\n    {\n      chsrc_run(\"tlmgr option repository\", RunOpt_Default);\n    }\n  if (mpm_exist)\n    {\n      chsrc_run(\"mpm --get-repository\", RunOpt_Default);\n    }\n}\n\n/**\n * @consult https://help.mirrors.cernet.edu.cn/CTAN/\n */\nvoid\nwr_tex_setsrc (char *option)\n{\n  bool tlmgr_exist, mpm_exist;\n  wr_tex_check_cmd (&tlmgr_exist, &mpm_exist);\n\n  chsrc_use_this_source (wr_tex);\n\n  char *cmd = NULL;\n\n  if (tlmgr_exist)\n    {\n      cmd = xy_2strcat (\"tlmgr option repository \", source.url);\n      chsrc_run (cmd, RunOpt_Default);\n    }\n\n  if (mpm_exist)\n    {\n      char *miktex_url = xy_2strcat (xy_str_delete_suffix (source.url, \"texlive/tlnet\"), \"win32/miktex/tm/packages/\");\n      cmd = xy_2strcat (\"mpm --set-repository=\", miktex_url);\n      chsrc_run (cmd, RunOpt_Default);\n    }\n\n  chsrc_determine_chgtype (ChgType_Untested);\n  chsrc_conclude (&source);\n}\n"
  },
  {
    "path": "src/recipe/ware/WinGet.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * ------------------------------------------------------------*/\n\ndef_target(wr_winget, \"winget\");\n\nvoid\nwr_winget_prelude ()\n{\n  chef_prep_this (wr_winget, gsr);\n\n  chef_set_recipe_created_on   (this, \"2024-06-07\");\n  chef_set_recipe_last_updated (this, \"2025-08-17\");\n  chef_set_sources_last_updated (this, \"2025-07-13\");\n\n  chef_set_chef (this, NULL);\n  chef_set_cooks (this, 1, \"@ccmywish\");\n  chef_set_sauciers (this, 1, \"@Mikachu2333\");\n\n  chef_set_scope_cap (this, ProjectScope, ScopeCap_Unable);\n  chef_set_scope_cap (this, UserScope,    ScopeCap_Able_And_Implemented);\n  chef_set_scope_cap (this, SystemScope,  ScopeCap_Unable);\n  chef_set_default_scope (this, UserScope);\n\n  chef_deny_english(this);\n  chef_allow_user_define(this);\n\n  def_sources_begin()\n  {&UpstreamProvider, \"https://cdn.winget.microsoft.com/cache\",    NULL},\n  {&MirrorZ,          \"https://mirrors.cernet.edu.cn/winget-source\", NULL},\n  {&Ustc,             \"https://mirrors.ustc.edu.cn/winget-source\", NULL},\n  {&Nju,              \"https://mirror.nju.edu.cn/winget-source\",   NULL},\n  {&Nyist,            \"https://mirror.nyist.edu.cn/winget-source\", NULL},\n  {&Xjtu,             \"https://mirrors.xjtu.edu.cn/winget-source\", NULL}\n  def_sources_end()\n}\n\n\nvoid\nwr_winget_getsrc (char *option)\n{\n  chsrc_run (\"winget source list\", RunOpt_Default);\n}\n\n\n/**\n * @consult https://mirrors.ustc.edu.cn/help/winget-source.html\n */\nvoid\nwr_winget_setsrc (char *option)\n{\n  chsrc_use_this_source (wr_winget);\n\n  // 2025.8.17 此前用户可能隐式使用默认源导致 remove 失败，故使用 Dont_Abort\n  chsrc_run (\"winget source remove winget\", RunOpt_Dont_Abort_On_Failure);\n  // 2025.8.18 执行两次相同的命令后继续设置，无报错，换源成功。具体原因不明\n  chsrc_run (\"winget source remove winget\", RunOpt_Dont_Abort_On_Failure);\n  chsrc_run (xy_strcat (3, \"winget source add winget \", source.url, \" --trust-level trusted\"), RunOpt_Default);\n\n  chsrc_determine_chgtype (ChgType_Auto);\n  chsrc_conclude (&source);\n}\n\n\nvoid\nwr_winget_resetsrc (char *option)\n{\n  chsrc_run (\"winget source reset winget\", RunOpt_Default);\n\n  chsrc_determine_chgtype (ChgType_Reset);\n  chsrc_conclude (NULL);\n}\n"
  },
  {
    "path": "src/resource/chsrc.rc",
    "content": "// chsrc.rc - Windows Resource Script\n// SPDX-License-Identifier: GPL-3.0-or-later\n\n#include <windows.h>\n#include \"../framework/version.h\"\n\n// 图标资源\nIDI_ICON1 ICON DISCARDABLE \"logo.ico\"\n\n// 版本信息\nVS_VERSION_INFO VERSIONINFO\n    FILEVERSION     Chsrc_Version_Major,Chsrc_Version_Minor,Chsrc_Version_Patch,Chsrc_Version_Pre\n    // 经实验，该值会被下面的 ProductVersion 替换\n    // PRODUCTVERSION  Chsrc_Version_Major,Chsrc_Version_Minor,Chsrc_Version_Patch,Chsrc_Version_Pre\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 \"040904b0\"\n        BEGIN\n            VALUE \"CompanyName\",      \"RubyMetric\"\n            VALUE \"FileDescription\",  \"Change Source everywhere for every software\"\n\n            // 经实验，该值会被上面的 FILEVERSION 替换\n            // VALUE \"FileVersion\",    Chsrc_Version\n\n            VALUE \"InternalName\",     \"chsrc\"\n            VALUE \"LegalCopyright\",   \"Copyright (c) 2023-2026 RubyMetric\"\n            VALUE \"OriginalFilename\", \"chsrc.exe\"\n            VALUE \"ProductName\",      \"chsrc\"\n            VALUE \"ProductVersion\",    Chsrc_Version\n            VALUE \"Comments\",         \"Released on \" Chsrc_Release_Date \" (GPLv3+)\"\n            VALUE \"LegalTrademarks\",  \"RubyMetric\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x0804, 1200, 0x0409, 1200  // 简体中文和英语\n    END\nEND\n"
  },
  {
    "path": "test/cli.pl",
    "content": "#!/usr/bin/env perl\n# ---------------------------------------------------------------\n# Test File     : cli.pl\n# Test Authors  : 曾奥然 <ccmywish@qq.com>\n# Contributors  : Nil Null <nil@null.org>\n# Created On    : <2024-06-05>\n# Last Modified : <2026-02-24>\n#\n# 测试 chsrc 可执行文件\n# ---------------------------------------------------------------\n\n=encoding utf8\n\n本文件可以使用\n\n    $ podchecker .test\\cli.pl\n\n来检查 Pod 语法\n\n    $ pod2html .\\test\\cli.pl > CLI.html\n\n来生成 HTML 文件\n\n    $ pod2markdown .\\test\\cli.pl > CLI.md\n\n来生成 Markdown 文件\n\n=over\n\n=item C<=end> 的时候前面必须给一个空行，否则 podchecker 不认\n\n=item 每一个 Pod block 必须用 C<=cut> 来终结，否则 VS Code 会把后续内容全部认为是 Pod\n\n=back\n=cut\n\n\nuse v5.42;\nuse utf8;\n# v5.38 还不用强制 utf8，现在代码里（包括注释）只要有其他字符，都必须强制使用 utf8\nuse Test::More;\n# `` 执行命令以后，返回的全部是字节流，而不是字符串，\n# chsrc 已经输出的是 UTF-8 字符串了，所以我们在这里需要\n# 设置该选项，将这些字节流编码为 UTF-8 才能得到我们想要的结果\nuse open qw(:std :encoding(UTF-8));\n\n=begin comment\n\n注意:\n\n    `./chsrc`\n\n在 Windows 上也是可以正常执行的，Perl 应该是内部进行了转换。然而，下面这一行却会报错：\n\n    `./chsrc get -no-color 2>&1`\n\n2>&1重定向虽然在 Windows CMD 中是正确的，但是在 Perl 中执行，却会反而把 ./chsrc 的问题给报出来。\n因此，我们需要对执行的命令进行处理\n\n=end comment\n=cut\n\nmy $CHSRC = ($^O eq 'MSWin32') ? '.\\chsrc' : './chsrc';\n\nmy $version_str_cn = qr|chsrc .*\\n\\nCopyright .*\\n许可证 GPLv3\\+：GNU GPL 第 3 版或更高版本|;\nlike `$CHSRC -v`,         $version_str_cn,  'chsrc -v';\nlike `$CHSRC --version`,  $version_str_cn,  'chsrc --version';\nlike `$CHSRC version`,    $version_str_cn,  'chsrc version';\n\nmy $version_str_en = qr|chsrc .*\\n\\nCopyright .*\\nLicense GPLv3\\+: GNU GPL version 3 or later|;\nlike `$CHSRC -v -en`,     $version_str_en,  'chsrc -v -en';\nlike `$CHSRC -en -v`,     $version_str_en,  'chsrc -en -v';\nlike `$CHSRC --version -en`,  $version_str_en,  'chsrc --version -en';\nlike `$CHSRC version -en`,    $version_str_en,  'chsrc version -en';\n\nmy $help_str = qr/^   (help|list|get|set|reset)/m;\nlike `$CHSRC -h`,     $help_str,    'chsrc -h';\nlike `$CHSRC --help`, $help_str,    'chsrc --help';\nlike `$CHSRC help`,   $help_str,    'chsrc help';\nlike `$CHSRC`,        $help_str,    'chsrc';\n\n\n=begin comment\n\n测试 chsrc list\n\n=end comment\n=cut\nmy $list_str = qr/mirrorz\\s*MirrorZ\\s*.*\\ntuna\\s*TUNA/;\nlike `$CHSRC ls`,            $list_str,    'chsrc ls';\nlike `$CHSRC list mirrors`,  $list_str,    'chsrc list mirrors';\nlike `$CHSRC list os`,    qr/netbsd\\s*openbsd/,   'chsrc list os';\nlike `$CHSRC list ware`,  qr/brew\\s*homebrew/,   'chsrc list ware';\n\n\n=begin comment\n\n测试 chsrc get\n\n=end comment\n=cut\nmy $get_null = qr/chsrc: 请提供想要查看源的目标名/u;\nlike `$CHSRC get -no-color 2>&1`,  $get_null,    'chsrc get -no-color';\n\nmy $fake_target_name = qr/暂不支持的换源目标/;\nlike `$CHSRC get fake_target_name 2>&1`,  $fake_target_name, 'chsrc get fake_target_name';\n\n\nif ((defined $ARGV[0]) && ($ARGV[0] eq 'fastcheck')) {\n    say \"Fast checking, done testing.\";\n    done_testing;\n    exit 0;\n}\n\nmy $has_ruby = system 'ruby -v';\nif ($has_ruby == 0) {\n    say \"Ruby exists. Go on testing.\";\n} else {\n    say \"No Ruby. End testing.\";\n    done_testing;\n    exit 0;\n}\n\nmy $get_ruby = qr/gem sources/;\nlike `$CHSRC get ruby`,   $get_ruby,  'chsrc get ruby';\n\n\n=begin comment\n\n测试 chsrc measure\n\n=end comment\n=cut\nmy $measure_ruby = qr/Ruby China 社区/;\nlike `$CHSRC measure ruby`,  $measure_ruby,  'chsrc measure ruby';\n\n\n=begin comment\n\n测试 chsrc set 以及 chsrc reset\n\n=end comment\n=cut\nmy $set_ruby_abcd      = qr/镜像站.*不存在/;\nmy $set_ruby_first     = qr/全自动换源完成, 感谢镜像提供方/;\nmy $set_ruby           = qr/全自动换源完成, 感谢镜像提供方/;\nmy $reset_ruby         = qr/选中镜像站.*Upstream.*已重置为上游默认源/s;\nmy $set_ruby_rubychina = qr/Ruby China 社区/;\nmy $set_ruby_locally   = qr/bundle config --local/;\n\nlike `$CHSRC set ruby abcd 2>&1`,      $set_ruby_abcd,      'chsrc set ruby abcd';\nlike `$CHSRC set ruby first`,          $set_ruby_first,     'chsrc set ruby first';\nlike `$CHSRC set ruby`,                $set_ruby,           'chsrc set ruby';\nlike `$CHSRC reset ruby`,              $reset_ruby,         'chsrc reset ruby';\nlike `$CHSRC set ruby rubychina`,      $set_ruby_rubychina, 'chsrc set ruby rubychina';\nlike `$CHSRC set -scope=project ruby first`,  $set_ruby_locally,  'chsrc set -scope=project ruby first';\n\n\ndone_testing;\n"
  },
  {
    "path": "test/fw.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------------------------------------------------------------\n * File Authors  : @ccmywish\n * Contributors  : @Mikachu2333\n * Created On    : <2024-12-14>\n * Last Modified : <2025-12-29>\n *\n * 该文件最好启用 DEBUG mode 编译\n * ------------------------------------------------------------*/\n\n#define Chsrc_Version \"Frameworker\"\n\n#include \"../src/framework/core.c\"\n\nint\nmain (int argc, char const *argv[])\n{\n  if (argc == 2 && xy_streql (argv[1], \"--version\"))\n    {\n      say (Chsrc_Version);\n      return 0;\n    }\n\n  xy_init ();\n\n  br();\n  chsrc_log  (\"chsrc_log\");\n  chsrc_succ (\"chsrc_succ\");\n  chsrc_info (\"chsrc_info\");\n  chsrc_warn (\"chsrc_warn\");\n  chsrc_error (\"chsrc_error\");\n  chsrc_debug (\"fw\", \"chsrc_debug\");\n  chsrc_verbose (\"chsrc_verbose\");\n\n  chsrc_succ2 (\"chsrc_succ2\");\n  chsrc_log2  (\"chsrc_log2\");\n  chsrc_note2 (\"chsrc_note2\");\n  chsrc_alert2 (\"chsrc_alert2\");\n  chsrc_warn2 (\"chsrc_warn2\");\n  chsrc_error2 (\"chsrc_error2\");\n  chsrc_debug2 (\"fw\", \"chsrc_debug2\");\n  chsrc_verbose2 (\"chsrc_verbose2\");\n\n  // 现在 chsrc_check_program() 无法检测本目录文件了\n  assert (chsrc_check_program (\"curl\"));\n  assert (chsrc_check_program_quietly (\"curl\"));\n  assert (chsrc_check_program_quietly_when_exist (\"curl\"));\n  chsrc_ensure_program (\"curl\");\n\n  chsrc_ensure_dir (\"test\");\n\n  char *tmpfile_content = \"Line2\\n\\nLine3\\n\";\n  char *tmpfile_name = \"test\";\n  char *tmpfile_ext = \".txt\";\n  char *tmpfile = \"\";\n\n  FILE *tmp = chsrc_make_tmpfile (tmpfile_name, tmpfile_ext, true, &tmpfile);\n  fwrite (tmpfile_content, sizeof (char), strlen (tmpfile_content), tmp);\n  fclose (tmp);\n\n  char *tmpfile_bk = xy_2strcat (tmpfile, \".bak\");\n\n  assert (xy_file_exist (tmpfile));\n  chsrc_backup (tmpfile);\\\n  assert (chsrc_check_file (tmpfile_bk));\n  remove (tmpfile_bk);\n\n  chsrc_append_to_file (\"Line4\\n\", tmpfile);\n  assert_str (xy_file_read (tmpfile), \"Line2\\n\\nLine3\\nLine4\\n\");\n\n  chsrc_prepend_to_file (\"Line1 \\n\", tmpfile);\n  assert_str (xy_file_read (tmpfile), \"Line1 \\nLine2\\n\\nLine3\\nLine4\\n\");\n\n  chsrc_overwrite_file (\"Line999 \\nLine998\\nLine997\\n\", tmpfile);\n  assert_str (xy_file_read (tmpfile), \"Line999 \\nLine998\\nLine997\\n\");\n\n  chsrc_log (xy_2strcat (\"CPU arch = \", chsrc_get_cpuarch ()));\n  print (\"chsrc: CPU cores = \");\n  println (chsrc_get_cpucore ());\n\n  remove (tmpfile);\n\n  // chsrc_run_in_inline_pwsh_shell (\"Write-Host \\\"Hello from inline PowerShell\\\"\");\n\n  if (xy.on_windows)\n    {\n      chsrc_view_env (\"OS\", \"windir\", NULL);\n      chsrc_run_as_pwsh_file (\"Write-Host \\\"Hello from PowerShell (v7) file\\\"\");\n      chsrc_run_as_powershellv5_file (\"Write-Host \\\"Hello from PowerShell v5 file\\\"\");\n      chsrc_run_as_powershell_file (\"Write-Host \\\"Hello from PowerShell file\\\"\");\n    }\n  else\n    {\n      chsrc_view_env (\"PWD\", NULL);\n      chsrc_run_as_sh_file (\"echo Hello from sh file\");\n      chsrc_run_as_bash_file (\"echo Hello from Bash file\");\n    }\n\n  chsrc_run (\"echo \" Chsrc_Version \" test pass!\", RunOpt_Dont_Notify_On_Success);\n  return 0;\n}\n"
  },
  {
    "path": "test/xy.c",
    "content": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: MIT\n * -------------------------------------------------------------\n * Test File     : xy.c\n * Test Authors  : 曾奥然 <ccmywish@qq.com>\n * Contributors  : Mikachu2333  <mikachu.23333@zohomail.com>\n * Created On    : <2023-08-30>\n * Last Modified : <2025-08-27>\n *\n * Test xy.h\n * ------------------------------------------------------------*/\n\n#include \"xy.h\"\n\nvoid\ncallback_print_str_for_seq (void *str, void *DUMMY)\n{\n  print ((char *) str);\n}\n\nvoid\ncallback_print_str_for_map (const char *key, void *value, void *DUMMY)\n{\n  println (xy_strcat (4, \"  \", key, \" => \", (char *) value));\n}\n\n\nint\nmain (int argc, char const *argv[])\n{\n  xy_init ();\n\n  // 关闭颜色\n  // xy.enable_color = false;\n\n  println (xy_os_depend_str (\"Hello, Windows!\", \"Hello, Unix!\"));\n\n  println (3);\n  double dbl = 3.1415;\n  println (dbl);\n  say (xy_2strcat (\"Xi\", \"'an\"));\n  say (xy_strcat  (2, \"Xi\", \"'an\"));\n  say (xy_strcat  (3, \"屈身守分，\", \"以待天时，\", \"不可与命争也\"));\n  say (xy_strcat  (4, \"水落鱼梁浅，\", \"天寒梦泽深。\", \"羊公碑字在，\", \"读罢泪沾襟。\"));\n  say (xy_strcat  (6, \"楚山横地出，\", \"汉水接天回。\", \"冠盖非新里，\", \"章华即旧台。\", \"习池风景异，\", \"归路满尘埃。\"));\n\n  print (xy_str_to_bold      (\"粗体\"));\n  print (xy_str_to_faint     (\"浅体\"));\n  print (xy_str_to_italic    (\"斜体\"));\n  print (xy_str_to_underline (\"下划线\"));\n  print (xy_str_to_blink     (\"闪烁\"));\n  print (xy_str_to_cross     (\"删除线\"));\n\n  print (xy_str_to_red     (\"红色\"));\n  print (xy_str_to_green   (\"绿色\"));\n  print (xy_str_to_yellow  (\"黄色\"));\n  print (xy_str_to_blue    (\"蓝色\"));\n  print (xy_str_to_magenta (\"紫色\"));\n  print (xy_str_to_purple  (\"紫色\"));\n  print (xy_str_to_cyan    (\"青色\"));\n  br();\n\n  xy_log   (\"普通\", \"输出普通内容\");\n  xy_succ  (\"成功\", \"输出成功内容\");\n  xy_info  (\"信息\", \"输出信息内容\");\n  xy_warn  (\"警告\", \"输出警告内容\");\n  xy_error (\"错误\", \"输出错误内容\");\n\n  xy_log_brkt   (\"xy.h\", \"普通\", \"咸阳油泼面筋道十足辣子香\");\n  xy_succ_brkt  (\"xy.h\", \"成功\", \"西安花干鸡蛋肉夹馍已出炉\");\n  xy_info_brkt  (\"xy.h\", \"信息\", \"襄阳牛肉面搭配黄酒更美味\");\n  xy_warn_brkt  (\"xy.h\", \"警告\", \"兰州牛肉面，而非兰州拉面\");\n  xy_error_brkt (\"xy.h\", \"错误\", \"西安肉丸胡辣汤里没有肉丸\");\n\n  assert (xy_streql    (\"abc\", \"abc\"));\n  assert (xy_streql_ic (\"abc\", \"abc\"));\n  assert (false == xy_streql (\"abc\", \"abC\"));\n  assert (true  == xy_streql_ic (\"abc\", \"abC\"));\n\n  assert (false == xy_str_end_with (\"abcdef\", \"abcdefg\"));\n  assert (xy_str_end_with (\"abcdef\", \"def\"));\n\n  assert (xy_str_end_with (\"abcdef\", \"bcdef\"));\n  assert (xy_str_end_with (\"abcdef\", \"abcdef\"));\n  assert (xy_str_end_with (\"abcdef\", \"\"));\n\n  assert (false == xy_str_start_with (\"abcdef\", \"abcdefg\"));\n  assert (xy_str_start_with (\"abcdef\", \"abc\"));\n  assert (xy_str_start_with (\"abcdef\", \"abcde\"));\n  assert (xy_str_start_with (\"abcdef\", \"abcdef\"));\n  assert (xy_str_start_with (\"abcdef\", \"\"));\n\n  assert_str (\"abcdefg\", xy_str_delete_suffix (\"abcdefg\", \"cdef\"));\n  assert_str (\"abcdefg\", xy_str_delete_suffix (\"abcdefg\", \"cdefgh\"));\n  assert_str (\"abcdefg\", xy_str_delete_suffix (\"abcdefg\", \"\"));\n  assert_str (\"abcd\",    xy_str_delete_suffix (\"abcdefg\", \"efg\"));\n\n  assert_str (\"abcdefg\", xy_str_delete_prefix (\"abcdefg\", \"cdef\"));\n  assert_str (\"abcdefg\", xy_str_delete_prefix (\"abcdefg\", \"0abcde\"));\n  assert_str (\"abcdefg\", xy_str_delete_prefix (\"abcdefg\", \"\"));\n  assert_str (\"defg\",    xy_str_delete_prefix (\"abcdefg\", \"abc\"));\n\n  assert_str (\"defdef\",   xy_str_gsub (\"abcdefabcdef\", \"abc\", \"\"));    // 删除\n  assert_str (\"6def6def\", xy_str_gsub (\"abcdefabcdef\", \"abc\", \"6\")); // 缩小\n  assert_str (\"XIANGdefXIANGdef\",\n              xy_str_gsub (\"abcdefabcdef\", \"abc\", \"XIANG\")); // 扩张\n  assert_str (\"DEFdefDEFdef\",\n              xy_str_gsub (\"abcdefabcdef\", \"abc\", \"DEF\")); // 等量\n\n\n  assert (xy_file_exist (\"./doc/image/chsrc.png\"));\n  assert (xy_dir_exist (\"~\"));\n  if (xy.on_windows)\n    {\n      say (xy_normalize_path (\"~\"));\n      say (xy_normalize_path (\"~/\"));\n      // xy_parent_dir() 得到的结果一定是不包含尾斜杠的目录名\n      assert_str (xy_parent_dir (xy_normalize_path (\"~\")), \"C:\\\\Users\");\n      assert_str (xy_parent_dir (xy_normalize_path (\"~/\")), \"C:\\\\Users\");\n      assert (xy_dir_exist (\"C:\\\\Users\"));\n\n      say (xy_win_powershell_profile);\n      say (xy_win_powershellv5_profile);\n      assert (xy_file_exist (xy_win_powershell_profile));\n      assert (true == xy_file_exist (xy_win_powershellv5_profile));\n\n      assert_str (xy_normalize_path (\"C:\\\\a bc\\\\def\\\\\"), \"C:\\\\a bc\\\\def\\\\\");\n      assert_str (xy_normalize_path (\"a/b c/d\"), \"a\\\\b c\\\\d\");\n      assert_str (xy_normalize_path (\"a/b c/d/\"), \"a\\\\b c\\\\d\\\\\");\n      assert_str (xy_parent_dir (\"a/b c/d\"), \"a\\\\b c\");\n      assert_str (xy_parent_dir (\"a/b c\\\\d/\"), \"a\\\\b c\");\n    }\n  else\n    {\n      /**\n       * debuild 过程会创建虚拟的 HOME 环境，导致检查 .bashrc 的测试会失败，所以我们先检查一下 .profile\n       * 如果没有，则大概率也没有 .bashrc\n       */\n      if (xy_file_exist (\"~/.profile\"))\n        {\n          assert (xy_file_exist (xy_bashrc));\n        }\n      assert (xy_dir_exist (\"/etc\"));\n    }\n\n  println (xy_normalize_path (\" \\n ~/haha/test/123 \\n\\r \"));\n  assert_str (xy_normalize_path (\"~/haha/test\"), xy_parent_dir (\" ~/haha/test/123\"));\n\n\n\n  XySeq_t *seq = xy_seq_new ();\n  xy_seq_push (seq, \"Hello\");\n  xy_seq_push (seq, \"World\");\n  assert_str (\"Hello\", xy_seq_at (seq, 1));\n  assert_str (\"World\", xy_seq_at (seq, 2));\n  xy_seq_each (seq, callback_print_str_for_seq, NULL); br();\n  xy_seq_pop (seq);\n  assert (1 == xy_seq_len (seq));\n\n\n  XyMap_t *map = xy_map_new ();\n  xy_map_set (map, \"Hello\", \"World\");\n  xy_map_set (map, \"你好\",  \"世界\");\n  assert_str (\"World\", xy_map_get (map, \"Hello\"));\n  assert_str (\"世界\", xy_map_get (map, \"你好\"));\n  xy_map_set (map, \"Hello\", \"chsrc\");\n  assert_str (\"chsrc\", xy_map_get (map, \"Hello\"));\n  assert (2 == xy_map_len (map));\n  echo (\"{\");\n    xy_map_each (map, callback_print_str_for_map, NULL);\n  echo (\"}\");\n\n  xy_succ (\"测试完成\", \"xy.h 测试全部通过\");\n\n  // xy_unimplemented();\n  // xy_unsupported();\n  // xy_unreached();\n  return 0;\n}\n"
  },
  {
    "path": "tool/README.md",
    "content": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! -------------------------------------------------------------\n ! Doc Type      : Markdown\n ! Doc Name      : (Tools Introduction).md\n ! Doc Authors   : 曾奥然  <ccmywish@qq.com>\n !               |  xuan   <wick.dynex@qq.com>\n ! Contributors  : ChatGPT <https://chatgpt.com>\n !               |\n ! Created On    : <2024-10-25>\n ! Last Modified : <2025-07-21>\n !\n ! tool 目录说明\n ! ---------------------------------------------------------- -->\n\n# 工具说明\n\n1. `installer.sh`\n\n    Bash 编写的一键安装工具\n\n2. `installer.ps1`\n\n    PowerShell 编写的一键安装工具\n\n3. `download-pre-on-GitHub.ps1`\n\n    从 GitHub `pre` release 上下载所有附件\n\n<br>\n\n## `rawstr4c`\n\nC语言字符串生成工具，本身是为了本项目而开发，是放在本仓库下的一个完整子项目。但为了维护更方便，拆分到新的仓库: <https://github.com/RubyMetric/rawstr4c>\n"
  },
  {
    "path": "tool/download-pre-on-GitHub.ps1",
    "content": "# ---------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# ---------------------------------------------------------------\n# File Name     : download-pre-on-GitHub.ps1\n# File Authors  : Aoran Zeng <ccmywish@qq.com>\n# Created On    : <2023-09-21>\n# Last Modified : <2025-08-07>\n#\n# Download all files from the `pre` release on GitHub:\n#   https://github.com/RubyMetric/chsrc/releases/tag/pre\n# ---------------------------------------------------------------\n\n$destination = \"~\\Desktop\\chsrc-pre-on-GitHub\"\n\nWrite-Output \"=> Mkdir $destination\"\nmkdir -Force $destination | Out-Null\n\n$destination = (Resolve-Path $destination).Path\n\n$names = @(\n    'chsrc-x64-windows.exe'\n    'chsrc-x86-windows.exe'\n\n    'chsrc-aarch64-macos'\n    'chsrc-x64-macos'\n\n    'chsrc-x64-linux'\n    'chsrc-aarch64-linux'\n    'chsrc-riscv64-linux'\n    'chsrc-armv7-linux'\n    'chsrc_latest-1_amd64.deb'\n\n    'chsrc-arm64-android'\n)\n\n# Like https://github.com/RubyMetric/chsrc/releases/download/latest/chsrc-x64-windows.exe\n$url_prefix = \"https://github.com/RubyMetric/chsrc/releases/download/pre/\"\n\nWrite-Output \"=> Starting downloads...\"\n\n$names | ForEach-Object -Parallel {\n    $name = $_\n    $url = $using:url_prefix + $name\n    $dest = $using:destination\n\n    Write-Output \"  - Downloading $name\"\n    # -s 阻止输出，避免并行输出混乱\n    # 此处必须使用绝对路径\n    curl -s -LO $url --output-dir $dest\n    Write-Output \"  √ Completed $name\"\n} -ThrottleLimit 5  # 限制同时下载5个文件\n\nWrite-Output \"=> All downloads completed!\"\n\nWrite-Output \"=> Downloaded to $destination\"\n"
  },
  {
    "path": "tool/git-ignore-vscode-settings.ps1",
    "content": "# ---------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# ---------------------------------------------------------------\n# File Name     : git-ignore-vscode-settings.ps1\n# File Authors  : Aoran Zeng <ccmywish@qq.com>\n# Created On    : <2025-08-17>\n# Last Modified : <2025-08-17>\n#\n# VS Code 的某些操作/插件会频繁地修改我们的 .vscode/settings.json\n# 文件，非常非常烦人，但是该文件又应该被加入仓库，所以我们使用以下\n# 命令来忽略它在本地的变化\n# ---------------------------------------------------------------\n\ngit update-index --skip-worktree .\\.vscode\\settings.json\n\n# 恢复方法是:\n# git update-index --no-skip-worktree .\\.vscode\\settings.json\n"
  },
  {
    "path": "tool/installer.ps1",
    "content": "# ---------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# ---------------------------------------------------------------\n# File Name     : installer.ps1\n# File Authors  :  xuan   <wick.dynex@qq.com>\n#               | ChatGPT <https://chatgpt.com/>\n#               | 曾奥然  <ccmywish@qq.com>\n# Contributors  : GitHub Copilot <https://github.com/copilot>\n#               |\n# Created On    : <2024-10-26>\n# Last Modified : <2026-01-06>\n#\n#         chsrc installer for Windows\n# ---------------------------------------------------------------\n\nparam(\n    [switch]\n    $Help,\n    $Directory = $null,\n    $Version = \"pre\"\n)\n\n\n$script:binary_name = \"chsrc\"\n$script:platform = \"Windows\"\n\n$script:install_dir = \"\"\n$script:arch = \"\"\n$script:target_version = \"\"\n$script:url = \"\"\n$script:create_dir_flag = $false\n\n\nfunction Help {\n    Write-Host\n@\"\nchsrc-installer: Install chsrc on ${script:platform}.\n\nUsage: install.ps1 [options]\nOptions:\n-h            Print this help information\n-d <dir>      Specify installation directory, default is current directory\n-v <version>  Specify chsrc version\n\n\"@\n}\n\n# 检查当前操作系统是否为 macOS 或 Linux\nif ($IsMacOS -or $IsLinux) {\n    Write-Host @\"\nSorry,\n\nThis installer is only available for ${script:platform}.\nIf you're looking for installation instructions for your operating system,\nplease visit the following link:\n\nhttps://github.com/RubyMetric/chsrc\n\"@\n    exit\n}\n\nif ($Help) {\n    Help\n    exit\n}\n\nfunction Output_Info () {\n    Write-Host \"[INFO] $args\"\n}\n\nfunction Output_Error () {\n    Write-Host \"[ERROR] $args\"\n    exit 1\n}\n\n\n# https://github.com/RubyMetric/chsrc/issues/332\nfunction Get_System_Downloads_Dir {\n    # 尝试从注册表获取实际的 Downloads 文件夹位置\n    try {\n        $shellFoldersKey = \"HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\"\n        $downloadsGuid = \"{374DE290-123F-4565-9164-39C4925E467B}\"\n        $downloadsPath = (Get-ItemProperty -Path $shellFoldersKey -Name $downloadsGuid -ErrorAction Stop).$downloadsGuid\n\n        # 展开环境变量 (例如 %USERPROFILE% -> C:\\Users\\xxx)\n        $downloadsPath = [System.Environment]::ExpandEnvironmentVariables($downloadsPath)\n\n        if (Test-Path -Path $downloadsPath -PathType Container) {\n            return $downloadsPath\n        }\n    } catch {\n        # 如果注册表读取失败，不输出错误信息，继续使用后备方案\n    }\n\n    # 后备方案：返回 null，稍后使用当前目录\n    return $null\n}\n\nfunction Set_Install_Dir {\n    # 如果用户未指定目录，则自动检测\n    if ($null -eq $Directory) {\n        # 尝试获取实际的 Downloads 目录\n        $detectedDownloads = Get_System_Downloads_Dir\n        if ($null -ne $detectedDownloads) {\n            $Directory = $detectedDownloads\n            Output_Info \"Detected Downloads directory: $Directory\"\n        } else {\n            # 使用当前目录作为默认值\n            $Directory = $PWD.Path\n            Output_Info \"Using current directory: $Directory\"\n        }\n    }\n\n    # 检查目录是否存在\n    if (-not (Test-Path -Path $Directory -PathType Container)) {\n        # 如果目录不存在，执行下面的代码块\n        try {\n            New-Item -Path $Directory -ItemType Directory -Force | Out-Null\n            Output_Info \"Directory created: $Directory\"\n            $script:create_dir_flag = $true\n        } catch {\n            Output_Error \"Failed to create directory: $_\"\n        }\n    }\n    $script:install_dir=$Directory\n    # 输出最终路径\n    Output_Info \"Set install dir to: $script:install_dir\"\n}\n\nfunction Set_Version {\n    $pattern = '^(0\\.[1-9]\\.[0-9]|pre)$'\n\n    if ($Version -notmatch $pattern) {\n        Output_Error \"Invalid version '$Version'. Please provide a valid version: 0.x.y (>=0.1.4) or 'pre'\"\n    }\n\n    # 设置版本号\n    $script:target_version=$Version\n    Output_Info \"Set chsrc version: $script:target_version\"\n}\n\nfunction Set_URL {\n    # 获取 CPU 型号\n    $cpuArchitecture = Get-WmiObject Win32_Processor `\n                        | Select-Object -First 1 -ExpandProperty Architecture\n\n    switch ($cpuArchitecture) {\n        0 { $script:arch = 'x86' }\n        9 {\n            # 如果是 64 位操作系统，选择 x64 安装包，否则选择 x86\n            if ([Environment]::Is64BitOperatingSystem) {\n                $script:arch = \"x64\"\n            }\n            else {\n                $script:arch = \"x86\"\n            }\n        }\n        default {\n            Output_Error \"Unsupported architecture '$cpuArchitecture'. Only x86 or x64 architectures are supported.\"\n        }\n    }\n    Output_Info \"Get my CPU architecture: $script:arch\"\n\n    # Set URL\n    if ($script:target_version -eq \"pre\") {\n        $script:url =  \"https://gitee.com/RubyMetric/chsrc/releases/download/\" + `\n                            \"${script:target_version}/chsrc-${script:arch}-windows.exe\"\n    }\n    else {\n        $script:url =  \"https://gitee.com/RubyMetric/chsrc/releases/download/\" + `\n                            \"v\" + \"${script:target_version}/chsrc-${script:arch}-windows.exe\"\n    }\n\n    Output_Info \"Set download URL: $script:url\"\n}\n\nfunction Install {\n    try {\n        # 设置安全协议为 TLS 1.2\n        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n\n        # 检查 URL 是否可访问\n        $response = Invoke-WebRequest -Uri $script:url -Method Head -ErrorAction Stop\n\n        if ($response.StatusCode -ne 200) {\n            Output_Error \"Unable to access $script:url. Status code: $($response.StatusCode)\"\n        }\n    }\n    catch {\n        Write-Host \"Unable to download ${script:binary_name}. Please check your internet connection.\"\n        exit 1\n    }\n\n    try {\n        $outfile = \"\\${script:binary_name}.exe\"\n        Output_Info \"Downloading $script:binary_name (architecture: $script:arch, platform: $script:platform, version: $script:target_version) to $script:install_dir\"\n        Invoke-WebRequest -OutFile ($script:install_dir + $outfile) -Uri $script:url -ErrorAction Stop\n        # 🎉 这个符号会变成 ??? 不要添加\n        Output_Info \"Installation completed, destination:\" ($script:install_dir + $outfile)\n    } catch {\n        Output_Error \"Unable to download $script:binary_name. Error: $_\"\n    }\n}\n\n\nfunction Cleanup {\n    if ($script:create_dir_flag -eq $true) {\n        if (Test-Path -Path $script:install_dir) {\n            Remove-Item -Path $script:install_dir -Recurse -Force  # 删除路径及其内容\n            Output_Info \"Deleted the directory: $script:install_dir\"\n        }\n    }\n}\n\n\n$null = Register-EngineEvent PowerShell.Exiting -Action { Cleanup }\n\n\n# main\nSet_Install_Dir\nSet_Version\nSet_URL\nInstall\n"
  },
  {
    "path": "tool/installer.sh",
    "content": "#!/usr/bin/env bash\n# ---------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# ---------------------------------------------------------------\n# File Name     :  installer.sh\n# File Authors  :    GnixAij     <gaojiaxing0220@gmail.com>\n#               |     xuan       <wick.dynex@qq.com>\n#               |    ChatGPT     <https://chatgpt.com>\n#               |   Aoran Zeng   <ccmywish@qq.com>\n# Contributors  : GitHub Copilot <https://github.com/copilot>\n#               |   DeepSeek     <https://chat.deepseek.com/>\n#               |\n# Created On    : <2024-10-25>\n# Last Modified : <2025-07-12>\n#\n#         chsrc installer for POSIX (mainly Linux & macOS)\n# ---------------------------------------------------------------\n\nbinary_name=\"chsrc\"\n\n# 用户指定的安装目录，函数set_install_dir()将填充/校验该变量\nuserOpt_install_dir=\"\"\n# 默认安装目录\ndefault_install_dir_4root=\"/usr/local/bin\"\ndefault_install_dir_4nonroot=\"$HOME/.local/bin\"\n\n# 若用户指定的目录不存在则会创建该目录\ntmp_created_install_dir=\"\"\n\nuserOpt_version=\"pre\"\nuserOpt_help=0\nuserOpt_lang=\"zh\"\n\n\n\ninfo() {\n  echo \"[INFO] $*\"\n}\n\nwarn() {\n  echo \"[WARN] $*\"\n}\n\nerror() {\n  echo \"[ERROR] $*\"\n}\n\n# 用户自己输入\ntypeit() {\n  echo \"[->] $ $*\"\n}\n\nerror_exit() {\n  echo -e \"[ERROR] $*\" >&2\n  exit 1\n}\n\n\nis_zh() {\n  if [ \"$userOpt_lang\" = \"zh\" ]; then\n    return 0\n  else\n    return 1\n  fi\n}\n\n\nhelp() {\n  if is_zh; then\n    echo \"chsrc-installer: 在类Unix操作系统上安装 chsrc\"\n    echo\n    echo \"使用: install.sh [选项]\"\n    echo \"选项:\"\n    echo \"-h            打印此帮助信息\"\n    echo \"-d <dir>      指定安装目录，默认为 $default_install_dir_4root 或 $default_install_dir_4nonroot\"\n    echo \"-v <version>  指定 chsrc 版本\"\n    echo \"-l <lang>     指定输出语言，支持 zh 和 en \"\n    echo\n  else\n    echo \"chsrc-installer: Install chsrc on any Unix-like OS\"\n    echo\n    echo \"Usage: install.sh [options]\"\n    echo \"Options:\"\n    echo \"-h            Print this help information\"\n    echo \"-d <dir>      Specify installation directory, default is $default_install_dir_4root OR $default_install_dir_4nonroot\"\n    echo \"-v <version>  Specify chsrc version\"\n    echo \"-l <lang>     Specify output language, supports zh and en\"\n    echo\n  fi\n}\n\n\nlet_user_build() {\n  if command -v make &>/dev/null; then\n    # 检测是否是 GNU make，如果是则用 make，如果不是则用C编译器来编译\n    if make --version | grep -q \"GNU Make\"; then\n      typeit \"make\"\n    else\n      if is_zh; then\n        warn \"检测到非 GNU make，本项目的Makefile仅支持GNU make\"\n      else\n        warn \"Non-GNU make was detected, the Makefile for this project only supports GNU make\"\n      fi\n      typeit \"cc/gcc/clang -Iinclude -Ilib src/chsrc-main.c -o chsrc\"\n    fi\n  else\n    if is_zh; then\n      warn \"未检测到GNU make，需手动执行编译命令：\"\n    else\n      warn \"GNU make was not detected, so we need to run the compile command manually:\"\n    fi\n    typeit \"cc/gcc/clang -Iinclude -Ilib src/chsrc-main.c -o chsrc\"\n  fi\n}\n\nlet_user_use_bootstrap() {\n  info \"请参考: https://github.com/RubyMetric/chsrc/tree/main/bootstrap 查找是否存在已有的 boostrapper\"\n}\n\n\nlet_user_compile() {\n  source_zip_url=\"https://gitee.com/RubyMetric/chsrc/repository/archive/main.zip\"\n  echo \"\"\n\n  if command -v git &>/dev/null; then\n    typeit \"git clone https://gitee.com/RubyMetric/chsrc.git\"\n    typeit \"cd chsrc\"\n    let_user_build\n    exit 1\n  elif command -v curl &>/dev/null; then\n    typeit \"curl -LO $source_zip_url\"\n  elif command -v wget &>/dev/null; then\n    typeit \"wget $source_zip_url\"\n  else\n    info \"Please download the source code: $source_zip_url\"\n  fi\n\n  typeit \"unzip ./main.zip \"\n  typeit \"cd ./chsrc-main\"\n  let_user_build\n  exit 1;\n}\n\n\n\nget_arch() {\n  echo $(uname -m | tr '[:upper:]' '[:lower:]')\n}\n\nget_platform() {\n  echo $(uname -s | awk '{print tolower($0)}')\n}\n\n# Linux   -> GNU/Linux\n# Android -> Android\nget_os() {\n  echo $(uname -o | awk '{print tolower($0)}')\n}\n\n\nset_arch() {\n  arch=$(get_arch)\n\n  case \"$arch\" in\n    x86_64)  arch=\"x64\" ;;\n    aarch64|arm64) arch=\"aarch64\" ;;\n    riscv64) arch=\"riscv64\" ;;\n    armv7*)  arch=\"armv7\" ;;\n    *)\n      if is_zh; then\n        warn \"抱歉, 暂无预编译二进制文件供你所在的平台架构: ${arch} 使用。请使用 chsrc-bootstrap 或 自行编译：\"\n      else\n        warn \"Sorry, No precompiled binaries for your arch: ${arch}. Please compile it on your own:\"\n      fi\n      let_user_use_bootstrap\n      let_user_compile\n      exit 1\n      ;;\n  esac\n}\n\n\nset_platform() {\n  platform=$(get_platform)\n\n  case \"$platform\" in\n    linux)\n      platform=\"linux\"\n      whatos=$(get_os)\n      if [ \"$whatos\" = \"android\" ]; then\n        if is_zh; then\n          info \"使用 chsrc-bootstrap: Termux\"\n        else\n          info \"Use chsrc-bootstrap: Termux\"\n        fi\n          wget -O - https://gitee.com/RubyMetric/chsrc/raw/main/bootstrap/Termux.bash | bash\n        exit 1\n      fi\n      ;;\n    darwin) platform=\"macos\" ;;\n    bsd|dragonfly)\n      platform=\"bsd\"\n      if is_zh; then\n        info \"抱歉, 暂无预编译二进制文件供BSD使用。请使用 chsrc-bootstrap 或 自行编译：\"\n      else\n        info \"Sorry, No precompiled binaries for BSD! Please compile it on your own:\"\n      fi\n      let_user_use_bootstrap\n      let_user_compile\n      exit 1\n      ;;\n    *)\n      if is_zh; then\n        error_exit \"抱歉，暂无预编译二进制文件供你所在的平台: ${platform} 使用。请使用 chsrc-bootstrap 或 自行编译：\"\n      else\n        error_exit \"Sorry, No precompiled binaries for your platform: ${platform}. Please compile it on your own:\"\n      fi\n      let_user_use_bootstrap\n      let_user_compile\n      exit 1\n      ;;\n  esac\n}\n\n\nset_binary_version() {\n  if [[ ! \"$userOpt_version\" =~ ^(pre|0\\.([1-9])\\.([0-9]))$ ]]; then\n      # version 不符合条件，报错\n      if is_zh; then\n        error_exit \"不支持的版本: ${userOpt_version}，版本号必须为 0.x.y (>=0.1.4) 或 'pre'\"\n      else\n        error_exit \"Unsupported version: ${userOpt_version}. Version number must be 0.x.y (>=0.1.4) or 'pre'\"\n      fi\n  fi\n\n  binary_version=\"${userOpt_version}\"\n\n  # version 版本不是 'pre'，添加'v'前缀\n  if [[ \"$userOpt_version\" =~ ^(0\\.([1-9])\\.([0-9]))$ ]]; then\n    binary_version=\"v${userOpt_version}\"\n  fi\n}\n\n\n#\n# 1. 若用户指定了安装目录，则安装至那里\n#\n#    若安装目录不存在，该脚本会为用户创建\n#\n# 2. 若用户没有指定安装目录:\n#\n#    2.1 若 chsrc 已存在，自动安装到该位置\n#    2.2 若 chsrc 不存在，安装到两个预定义的默认安装位置\n#\nset_install_dir() {\n  if [ -n \"$userOpt_install_dir\" ]; then\n    # 扩展 ~ 符号\n    userOpt_install_dir=\"${userOpt_install_dir/#\\~/$HOME}\"\n\n    # 检查目录是否存在，如果不存在则创建该目录\n    if [ ! -d \"$userOpt_install_dir\" ]; then\n\n      if is_zh; then\n        echo \"目录 $userOpt_install_dir 不存在，正在创建...\"\n      else\n        echo \"Directory $userOpt_install_dir does not exist. Creating...\"\n      fi\n\n      if ! mkdir -p \"$userOpt_install_dir\"; then\n        if is_zh; then\n          echo \"创建目录失败，请重试\"\n        else\n          echo \"Failed to create directory, please try again\"\n        fi\n        exit 1\n      fi\n\n      tmp_created_install_dir=\"$userOpt_install_dir\"  # 记录临时安装目录\n    fi\n\n  elif existing_path=$(command -v \"$binary_name\" 2>/dev/null); then\n\n    if is_zh; then\n      info \"$binary_name 已安装，更新路径: ${existing_path}\"\n    else\n      info \"$binary_name is already installed, updating path: ${existing_path}\"\n    fi\n\n    userOpt_install_dir=$(dirname \"$existing_path\")\n\n    if [ ! -w \"$userOpt_install_dir\" ]; then\n      if is_zh; then\n        error_exit \"目录 $userOpt_install_dir 不可写，请使用 sudo 命令运行脚本；或通过 -d 参数指定其它目录安装\"\n      else\n        error_exit \"Directory $userOpt_install_dir is not writable. Please run the script with sudo; or specify another dir using the -d option.\"\n      fi\n    fi\n\n  else\n    # 检查默认安装目录\n    if [ -d \"$default_install_dir_4root\" ] && [ -w \"$default_install_dir_4root\" ]; then\n      userOpt_install_dir=\"$default_install_dir_4root\"\n    elif [ -d \"$default_install_dir_4nonroot\" ] && [ -w \"$default_install_dir_4nonroot\" ]; then\n      userOpt_install_dir=\"$default_install_dir_4nonroot\"\n    else\n      if is_zh; then\n        error_exit \"默认安装目录 $default_install_dir_4root 和 $default_install_dir_4nonroot 不可写，请使用 sudo 命令运行脚本；或通过 -d 参数指定其它目录安装\"\n      else\n        error_exit \"Default install dir $default_install_dir_4root and $default_install_dir_4nonroot is not writable. Please run the script with sudo; or specify another dir using the -d option.\"\n      fi\n    fi\n  fi\n}\n\n#\n# @param $1: 下载链接\n# @param $2: 保存路径(带文件名)\n#\ndownload() {\n  if command -v curl &>/dev/null; then\n    curl -sL \"$1\" -o \"$2\"\n    return $? # 只能单独 return\n  fi\n\n  if command -v wget &>/dev/null; then\n    # follow 是wget默认行为\n    wget -qO \"$2\" \"$1\"\n    return $?\n  fi\n\n  if is_zh; then\n    error_exit \"缺乏必要的下载工具(curl或wget)，无法下载文件\"\n  else\n    error_exit \"Missing necessary download tools (curl or wget) to download the file!\"\n  fi\n}\n\n\ninstall() {\n\n  set_binary_version\n\n  set_arch\n\n  set_platform\n\n  set_install_dir\n\n  url=\"https://gitee.com/RubyMetric/chsrc/releases/download/${binary_version}/${binary_name}-${arch}-${platform}\"\n\n  path_to_executable=\"${userOpt_install_dir}/${binary_name}\"\n\n  if is_zh; then\n    info \"下载 ${binary_name} (架构: ${arch}, 平台: ${platform}, 版本: ${binary_version}) 到 ${path_to_executable}\"\n  else\n    info \"Downloading ${binary_name} (arch: ${arch}, platform: ${platform}, version: ${binary_version}) to ${path_to_executable}\"\n  fi\n\n  if download $url \"$path_to_executable\"; then\n    chmod +x \"$path_to_executable\"\n\n    if is_zh; then\n      info \"🎉 安装完成，路径: $path_to_executable\"\n    else\n      info \"🎉 Installation completed, path: $path_to_executable\"\n    fi\n  else\n    if is_zh; then\n      error_exit \"下载失败，请检查网络连接和代理设置: ${url}\"\n    else\n      error_exit \"Download failed, please check your network connection and proxy settings: ${url}\"\n    fi\n  fi\n}\n\n\ncleanup() {\n  if [ -n \"$tmp_created_install_dir\" ] && [ -d \"$tmp_created_install_dir\" ]; then\n\n    if is_zh; then\n      echo \"清理创建的目录: $tmp_created_install_dir\"\n    else\n      echo \"Cleaning up created directory: $tmp_created_install_dir\"\n    fi\n    rm -rf \"$tmp_created_install_dir\"\n  fi\n}\n\ntrap cleanup EXIT\n\n\n# main\nwhile getopts \":hd:v:l:\" option; do\n  case $option in\n  h)\n    userOpt_help=1\n    ;;\n  d)\n    userOpt_install_dir=${OPTARG}\n    ;;\n  v)\n    userOpt_version=${OPTARG}\n    ;;\n  l)\n    userOpt_lang=${OPTARG}\n    ;;\n  \\?)\n    echo \"无效的命令行选项，请使用 -h 查看帮助\"\n    exit 1\n    ;;\n  esac\ndone\n\nif [[ \"$userOpt_lang\" != \"zh\" && \"$userOpt_lang\" != \"en\" ]]; then\n  error_exit \"无效的语言选项: $userOpt_lang，支持的选项为 zh 和 en\"\nfi\n\nif [ \"$userOpt_help\" -eq 1 ]; then\n  help\n  exit 0;\nfi\n\ninstall\n"
  }
]