Full Code of RubyMetric/chsrc for AI

main a56f330d03ce cached
178 files
569.3 KB
192.5k tokens
391 symbols
1 requests
Download .txt
Showing preview only (612K chars total). Download the full file or copy to clipboard to get everything.
Repository: RubyMetric/chsrc
Branch: main
Commit: a56f330d03ce
Files: 178
Total size: 569.3 KB

Directory structure:
gitextract_0jn8y55u/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── 01-Report_Bug.yml
│   │   ├── 02-Request_Recipe.yml
│   │   ├── 03-Share.yml
│   │   ├── 04-Deprecate.yml
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE/
│   │   ├── Add_Feature.md
│   │   ├── Clean.md
│   │   ├── Enhance.md
│   │   ├── Fix_Bug.md
│   │   ├── Implement.md
│   │   ├── Refactor.md
│   │   └── Relate_Mirror_Source.md
│   ├── READIT.md
│   ├── copilot-instructions.md
│   ├── dependabot.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── PR-notify.yml
│       ├── PR-test.yml
│       ├── build-on-Linux-AArch64.yml
│       ├── build-on-Linux-ARMv7.yml
│       ├── build-on-Linux-riscv64.yml
│       ├── build-on-Linux-x64.yml
│       ├── build-on-Windows.yml
│       ├── build-on-macOS.yml
│       ├── pkg-deb.yml
│       ├── pub-AUR-chsrc-and-chsrc-bin.yml
│       ├── pub-AUR-chsrc-git.yml
│       └── pub-WinGet.yml
├── .gitignore
├── .vscode/
│   ├── README.md
│   ├── c_cpp_properties.json
│   ├── extensions.json
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── COPYING
├── LICENSE-MIT.txt
├── Makefile
├── README.md
├── bootstrap/
│   ├── README.md
│   └── Termux.bash
├── doc/
│   ├── 01-开发与构建.md
│   ├── 02-提交与贡献.md
│   ├── 03-为什么拒绝使用代码格式化工具.md
│   ├── 10-如何编写recipe.md
│   ├── 11-如何设置换源链接与测速链接.md
│   ├── 50-协作者与维护者.md
│   ├── README.md
│   ├── chsrc.1
│   └── chsrc.texi
├── include/
│   └── .keep
├── justfile
├── lefthook.yml
├── lib/
│   └── xy.h
├── pkg/
│   ├── AUR/
│   │   └── README.md
│   ├── README.md
│   └── deb/
│       ├── BUILD.md
│       ├── CI.md
│       ├── Makefile
│       ├── README.md
│       ├── deb-installation-test.sh
│       └── debian/
│           ├── changelog
│           ├── control
│           ├── copyright
│           ├── postinst
│           ├── prerm
│           └── rules
├── src/
│   ├── chsrc-main.c
│   ├── framework/
│   │   ├── chef.c
│   │   ├── core.c
│   │   ├── helper.c
│   │   ├── mirror.c
│   │   ├── struct.h
│   │   └── version.h
│   ├── rawstr4c.h
│   ├── rawstr4c.md
│   ├── recipe/
│   │   ├── lang/
│   │   │   ├── Clojure.c
│   │   │   ├── Dart/
│   │   │   │   ├── Flutter.c
│   │   │   │   ├── Pub.c
│   │   │   │   └── common.h
│   │   │   ├── Go.c
│   │   │   ├── Haskell.c
│   │   │   ├── Java.c
│   │   │   ├── JavaScript/
│   │   │   │   ├── Bun.c
│   │   │   │   ├── JavaScript.c
│   │   │   │   ├── Yarn.c
│   │   │   │   ├── common.h
│   │   │   │   ├── npm.c
│   │   │   │   ├── nvm.c
│   │   │   │   └── pnpm.c
│   │   │   ├── Julia.c
│   │   │   ├── Lua.c
│   │   │   ├── NuGet.c
│   │   │   ├── OCaml.c
│   │   │   ├── PHP.c
│   │   │   ├── Perl.c
│   │   │   ├── Python/
│   │   │   │   ├── PDM.c
│   │   │   │   ├── Poetry.c
│   │   │   │   ├── Python.c
│   │   │   │   ├── Rye.c
│   │   │   │   ├── common.h
│   │   │   │   ├── pip.c
│   │   │   │   ├── rawstr4c.h
│   │   │   │   ├── rawstr4c.md
│   │   │   │   └── uv.c
│   │   │   ├── R.c
│   │   │   ├── Ruby/
│   │   │   │   ├── README.md
│   │   │   │   └── Ruby.c
│   │   │   ├── Rust/
│   │   │   │   ├── Cargo.c
│   │   │   │   ├── common.h
│   │   │   │   └── rustup.c
│   │   │   ├── rawstr4c.h
│   │   │   └── rawstr4c.md
│   │   ├── menu.c
│   │   ├── os/
│   │   │   ├── APT/
│   │   │   │   ├── Armbian.c
│   │   │   │   ├── Debian.c
│   │   │   │   ├── Kali-Linux.c
│   │   │   │   ├── Linux-Lite.c
│   │   │   │   ├── Linux-Mint.c
│   │   │   │   ├── ROS.c
│   │   │   │   ├── Raspberry-Pi-OS.c
│   │   │   │   ├── Termux.c
│   │   │   │   ├── Trisquel.c
│   │   │   │   ├── Ubuntu.c
│   │   │   │   ├── common.h
│   │   │   │   ├── deepin.c
│   │   │   │   ├── openKylin.c
│   │   │   │   ├── rawstr4c.h
│   │   │   │   └── rawstr4c.md
│   │   │   ├── Alpine-Linux.c
│   │   │   ├── BSD/
│   │   │   │   ├── FreeBSD.c
│   │   │   │   ├── NetBSD.c
│   │   │   │   └── OpenBSD.c
│   │   │   ├── Gentoo-Linux.c
│   │   │   ├── OpenWrt.c
│   │   │   ├── Solus.c
│   │   │   ├── Void-Linux.c
│   │   │   ├── YUM/
│   │   │   │   ├── AlmaLinux.c
│   │   │   │   ├── Anolis-OS.c
│   │   │   │   ├── Fedora-Linux.c
│   │   │   │   ├── Rocky-Linux.c
│   │   │   │   ├── common.h
│   │   │   │   └── openEuler.c
│   │   │   ├── openSUSE.c
│   │   │   ├── pacman/
│   │   │   │   ├── Arch-Linux.c
│   │   │   │   ├── MSYS2.c
│   │   │   │   └── Manjaro-Linux.c
│   │   │   ├── rawstr4c.h
│   │   │   └── rawstr4c.md
│   │   ├── recipe-template.c
│   │   └── ware/
│   │       ├── Anaconda/
│   │       │   ├── Anaconda.c
│   │       │   ├── rawstr4c.h
│   │       │   └── rawstr4c.md
│   │       ├── CocoaPods.c
│   │       ├── Docker/
│   │       │   ├── Docker.c
│   │       │   ├── README.md
│   │       │   ├── rawstr4c.h
│   │       │   └── rawstr4c.md
│   │       ├── Emacs.c
│   │       ├── Flatpak.c
│   │       ├── Guix.c
│   │       ├── Homebrew/
│   │       │   ├── Homebrew.c
│   │       │   ├── rawstr4c.h
│   │       │   └── rawstr4c.md
│   │       ├── Nix.c
│   │       ├── TeX-Live.c
│   │       └── WinGet.c
│   └── resource/
│       └── chsrc.rc
├── test/
│   ├── cli.pl
│   ├── fw.c
│   └── xy.c
└── tool/
    ├── README.md
    ├── download-pre-on-GitHub.ps1
    ├── git-ignore-vscode-settings.ps1
    ├── installer.ps1
    └── installer.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# --------------------------------------------------------------
# SPDX-License-Identifier: GPL-3.0-or-later
# --------------------------------------------------------------
# Config Type   : EditorConfig
# Config Authors: 曾奥然 <ccmywish@qq.com>
# Contributors  : Nil Null <nil@null.org>
# Created On    : <2023-09-06>
# Last Modified : <2025-08-27>
#
# 请参考 ./doc/03-为什么拒绝使用代码格式化工具.md
#
# http://editorconfig.org
# --------------------------------------------------------------

root = true

[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true

# VS Code 对该配置(为 false)的实现有问题,这是确定的,
# 然而 CLion 似乎对该配置(为 false)的实现是正确的,这导致不同贡献者反而产生了冲突
# 所以我们现在改成 true
insert_final_newline = true

[*.{c,C,cpp,cxx,cc,h,hpp}]
indent_style = space
indent_size = 2

[*.pl]
indent_size = 4

[*.{raku,rakumod,rakutest}]
indent_size = 2

[*.ps1]
indent_size = 4

[*.{sh,bash}]
indent_size = 2

[Makefile,makefile,*.{mk,make,makefile}]
indent_style = tab

# 使用 VS Code 生成文件的默认格式
[*.json]
indent_size = 4

[*.{yaml,yml}]
indent_size = 2


================================================
FILE: .github/FUNDING.yml
================================================
custom: [
  'https://afdian.com/a/ccmywish',
  'https://github.com/ccmywish/support-my-oss-work'
]


================================================
FILE: .github/ISSUE_TEMPLATE/01-Report_Bug.yml
================================================
name: 🐞 Bug 报告
description: 有 Bug 了吗?
title: "详细报告BUG是chsrc用户的一大美德"
# labels: [ ]
type: Bug
body:
  - type: markdown
    attributes:
      value: |
        感谢花时间填写此 Bug 报告!

        1. 你可能是通过包管理器安装的 `chsrc`,其版本往往稍旧,你可先尝试使用REAME中提供的安装命令来获取最新版本

        2. 有时 Bug 是在最新版本中引入的,此时你可在安装命令时指定 `-v` 参数临时使用旧版本解决燃眉之急,详情查看README

  - type: textarea
    id: what-did-you-do
    attributes:
      label: 你操作了什么?
      # description: 告诉我们,在问题出现之前你使用 chsrc 做了什么?
      placeholder: 我运行了 chsrc set <target>...
    validations:
      required: true

  - type: textarea
    id: what-happened
    attributes:
      label: 发生了什么?
      # description: 告诉我们,发生了什么你认为不该出现的事?屏幕截图或视频记录都很有帮助
      placeholder: 换源没有成功...
    validations:
      required: true

  - type: textarea
    id: what-should-happen
    attributes:
      label: 本应该怎么样?
      # description: 告诉我们,正常的或你期望看到的 运行结果和状态
      placeholder: 我希望 chsrc 成功帮我换源...
    validations:
      required: true

  - type: input
    id: version
    attributes:
      label: chsrc 版本
      # description: 你正在使用 chsrc 哪个版本?
      placeholder: 请使用 chsrc -h 或 chsrc -v 查看,并*复制发布日期*
    validations:
      required: true

  - type: dropdown
    id: os
    attributes:
      label: 你使用的是哪个操作系统?
      multiple: true
      options:
        - Windows
        - Linux
        - macOS
        - FreeBSD
        - NetBSD
        - OpenBSD
        - 其他
    validations:
      required: true

  - type: input
    id: os-version
    attributes:
      label: OS 版本 / OS 发行版
      # description: ""
      placeholder: "请告诉我们具体的OS版本或发行版,如 Windows 11, Ubuntu Linux 24.04... 等等"
    validations:
      required: false

  - type: textarea
    id: logs
    attributes:
      label: Log 输出
      description: 请复制粘贴任何相关的 Log 输出。此内容将自动格式化为代码块,因此不需要反引号
      render: shell

  - type: checkboxes
    id: terms
    attributes:
      label: 防止重复问题
      description: 请确认在打开这个新的 issue 之前已经搜索过类似的issue。你可以评论或订阅已经存在的相关 issue
      options:
        - label: 我已在项目中搜索过类似的 issue
          required: true


================================================
FILE: .github/ISSUE_TEMPLATE/02-Request_Recipe.yml
================================================
name: 🫡 我想要对 target 换源!
description: 想要对尚未支持的 target 进行换源?
title: "提前找好方案怎么换源是chsrc用户的一大美德"
# labels: [ ]
type: Request
body:
  - type: markdown
    attributes:
      value: |
        请先回答这些问题

  - type: textarea
    id: description
    attributes:
      label: 描述新的换源目标
      placeholder: 它是编程语言、操作系统还是一个普通软件?
    validations:
      required: true

  - type: textarea
    id: reference-solution
    attributes:
      label: 请尽可能提供可参考的换源方法
      placeholder: 往往提供该源的镜像站会附带换源方法,可以提供给我们参考
    validations:
      required: true

  - type: textarea
    id: mirrors
    attributes:
      label: 请尽可能提供已有镜像站
      placeholder: 当你提出该请求的时候,你可能已有心仪的镜像站,请告诉我们以避免重复查找劳动
    validations:
      required: true


================================================
FILE: .github/ISSUE_TEMPLATE/03-Share.yml
================================================
name: 🎉 我找到了新的镜像站或源!
description: 为大家分享新的镜像站或可用源!
title: "分享是chsrc用户的一大美德"
# labels: [ ]
type: Contribute
body:
  - type: markdown
    attributes:
      value: |
        感谢你的分享!这将使你与更广大的用户得到更多可选的服务!同时也让镜像站开发维护人员更加有使命感!

  - type: textarea
    id: description
    attributes:
      label: 描述该镜像站或该源
      description: |
        1. 请告诉我们该镜像站的主体URL
        2. 你是否已经测试过该镜像站的可用性?
        3. 它大概提供哪些源?
        4. 你想要我们为你添加该镜像站的具体哪个源?
    validations:
      required: true


================================================
FILE: .github/ISSUE_TEMPLATE/04-Deprecate.yml
================================================
name: ⛓️‍💥 镜像源已失效
description: 该镜像站已关停/该源已不再被支持
title: "报告镜像源情况是chsrc用户的一大美德"
# labels: [ ]
type: Deprecate
body:
  - type: markdown
    attributes:
      value: |
        感谢你的一手消息!让用户不再疑惑是哪里出了错!

  - type: textarea
    id: description
    attributes:
      label: 什么被弃用了?
      description: |
        1. 请告诉我们是镜像站还是某个源失效
        2. 如果可能,你可以开启该issue后参与维护!在代码中删除掉该源并不复杂!
    validations:
      required: true


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
  - name: ❤️ 赞赏支持 chsrc
    url: https://afdian.com/a/ccmywish
    # about 不支持 Markdown 语法
    about: 你是否因为 chsrc 而受到启发、节省了时间精力 or whatever?


================================================
FILE: .github/PULL_REQUEST_TEMPLATE/Add_Feature.md
================================================
## 新功能描述

请描述该新功能,为什么要增加这个功能,以及具体的用例

---

## 方案

请介绍你新增加该功能的方案

---

## 实现

请介绍你的实现(若实现相当直接则不需要描述)


================================================
FILE: .github/PULL_REQUEST_TEMPLATE/Clean.md
================================================
## 描述

注意: 小改动请使用该PR模板。而中等、大型规模的变化,或者引起巨大联动变化的改动,需要使用 `Refactor` PR模板。

请介绍你进行了什么清理,如某部分代码,如某部分文档

---

## 方案

请介绍你进行清理的方案(如果你认为有必要的话)

---

## 实现

请介绍你的实现(若实现相当直接则不需要描述)


================================================
FILE: .github/PULL_REQUEST_TEMPLATE/Enhance.md
================================================
## 改进描述

请描述要改进的具体内容,为什么要增强/改善它,以及具体的用例

---

## 方案

请介绍你的改进方案

---

## 实现

请介绍你的实现(若实现相当直接则不需要描述)


================================================
FILE: .github/PULL_REQUEST_TEMPLATE/Fix_Bug.md
================================================
## Bug 背景

请介绍 Bug 的背景以及相关 issue

---

## Bug 原因

请描述导致 Bug 的具体原因

---

## 方案

请介绍你的修复方案

---

## 实现

请介绍你的实现(若实现相当直接则不需要描述)


================================================
FILE: .github/PULL_REQUEST_TEMPLATE/Implement.md
================================================
## 问题描述

(此内容必填)

1. 简要说明此 PR 修复的具体问题或改进的功能背景
2. 列出与此 PR 相关的 issue 或任务,若没有填 `N/A`

<br>



## 方案

(此内容必填)

详细描述针对该问题或功能改进的解决方案

<br>



## 实现

(此内容可选填)

在按照上述方案实现时,若遇到需记录和提醒他人的细节时,务必在此描述

<br>



## 测试

(此内容可选填)

描述如何验证本 PR,列出具体的测试步骤

<br>



## 备注

(此内容可选填)

列出需要特别注意或额外注意的事项

<br>


================================================
FILE: .github/PULL_REQUEST_TEMPLATE/Refactor.md
================================================
## 背景

注意: 中等、大型规模的变化,或者引起巨大联动变化的改动,才需要使用该模板。中小改动请使用 `Clean` PR模板。

请介绍该重构的背景,可以带来哪些优势?

---

## 方案

请介绍你进行重构的方案

---

## 实现

请介绍你的实现(若实现相当直接则不需要描述)


================================================
FILE: .github/PULL_REQUEST_TEMPLATE/Relate_Mirror_Source.md
================================================
## 可用性确认

1. 请你本人确认这些源真的可用或已经失效,不要等待其它用户帮你测试

2. 请确保修改后代码依然可以编译及运行

3. 请在你修改的各个文件的标头部分增加你自己的贡献信息,名字栏需要为中文拼音、或者英文名、或者账号名


================================================
FILE: .github/READIT.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : (Overview .github) READIT.md
 ! Doc Authors   : 曾奥然 <ccmywish@qq.com>
 ! Contributors  : Nul None <nul@none.org>
 !               |
 ! Created On    : <2025-06-20>
 ! Last Modified : <2025-06-20>
 !
 ! 此文件不能叫做 README.md,否则 GitHub 主页会显示此文件
 ! ---------------------------------------------------------- -->

[`pull_request_template.md`](./pull_request_template.md) 是 [`PULL_REQUEST_TEMPLATE/Implement.md`](./PULL_REQUEST_TEMPLATE/Implement.md) 的最简化版


================================================
FILE: .github/copilot-instructions.md
================================================
# chsrc Project Rules for AI Assistants

## 项目概述

这是 chsrc 项目,一个用 C 语言编写的跨平台命令行换源工具,帮助用户在不同的镜像之间切换,适用于编程语言、操作系统、其他软件。它的最强大之处在于它是一个框架,能够帮助用户轻松地为不同的目标换源。


## 架构

- **Framework**: 在目录 `src/framework/` 中,包含了核心实现,支持 recipe

  - `struct.h` 里定义了各种数据结构和宏,这是整个 chsrc 的核心,也是 chef DSL 的核心
  - `chef.c` 里实现了 chef DSL,你可以使用它来确定正确的使用方法

- **Recipes**: 在目录 `src/recipe/` 中,包含了针对不同目标的具体实现

  - `lang/` - 编程语言 (Ruby, JavaScript 等等)
  - `os/`   - 操作系统 (Ubuntu, Arch Linux 等等)
  - `ware/` - 软件工具和应用 (Docker, Homebrew 等等)


## Coding Guidelines

### C Coding Style:

请阅读 `doc/03-为什么拒绝使用代码格式化工具.md`

### Important Project Concepts:

请阅读 `doc/10-如何编写recipe.md`

## Important: 一定要保持注释,因为它记录了重要的维护信息


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: github-actions
    directory: "/"
    schedule:
      interval: weekly


================================================
FILE: .github/pull_request_template.md
================================================
## 问题描述

1. 简要说明此 PR 修复的具体问题或改进的功能背景
2. 列出与此 PR 相关的 issue 或任务,若没有填 `N/A`

<br>



## 方案与实现

详细描述针对该问题或功能改进的解决方案

<br>


================================================
FILE: .github/workflows/PR-notify.yml
================================================
# ---------------------------------------------------------------
# Workflow File : PR-notify.yml
# File Authors  : 曾奥然 <ccmywish@qq.com>
# Contributors  : Nul None <nul@none.org>
#               |
# Created On    : <2025-06-19>
# Last Modified : <2025-08-07>
#
# Notify PR
# ---------------------------------------------------------------

name: 告知PR者

on:
  pull_request_target:
    types: [opened,
            ready_for_review, # draft PR 转为正式 PR
            review_requested,
            reopened]

jobs:
  enforce-dev-branch:
    name: 强制使用dev分支
    runs-on: ubuntu-latest
    # github.event.pull_request_target 内容为空,转而用 pull_request
    if: github.event.pull_request.base.ref != 'dev'
    steps:
      - name: 评论
        uses: thollander/actions-comment-pull-request@v3
        with:
          message: |
            Hi @${{github.event.pull_request.user.login}},

            ❤️ 感谢你的贡献!你的 PR 当前基于 `${{github.base_ref}}` 分支,请修改使用 `dev` 分支
          comment-tag: "❤️ 感谢你的贡献!"
      - run: |
          echo "::error::❌ PR 必须以 dev 分支为目标!当前是 ${GITHUB_BASE_REF}"
          exit 1

  welcome:
    name: 欢迎PR者
    runs-on: ubuntu-latest
    # 仅在 opened 时欢迎,其他情况都不再重复欢迎了
    if: github.event.pull_request.base.ref == 'dev' && github.event.action == 'opened'
    steps:
      - name: 查看 GitHub Actions 环境
        run: |
          echo "Event 类型: ${{ github.event.action }}"
          echo "Event 名: ${{ github.event_name }}"

      # 2025-10-06 移除点赞的步骤
      # 因原 peter-evans/create-or-update-comment@v5 已不再支持空body,而如果使用 Github Token 之类又过于大材小用因此移除

      - name: 添加评论欢迎 PRer
        uses: peter-evans/create-or-update-comment@v5
        with:
          issue-number: ${{ github.event.pull_request.number }}
          body: |
            Hi @${{github.event.pull_request.user.login}}

            ❤️ 感谢你的贡献!我们将在最少半小时,最多5天内阅读此 PR 并回复你
          edit-mode: replace


================================================
FILE: .github/workflows/PR-test.yml
================================================
# ---------------------------------------------------------------
# Workflow File : PR-test.yml
# File Authors  : 曾奥然 <ccmywish@qq.com>
# Contributors  : Mikachu2333 <mikachu2333@zohomail.com>
#               |
# Created On    : <2025-06-19>
# Last Modified : <2025-08-17>
#
# Test PR
# ---------------------------------------------------------------

name: 测试PR

on:
  pull_request:
    # 仅在开 pr、草稿转正式、手动要求 review、reopen的时候运行测试
    types: [
        opened,
        # 因 synchronize 将导致 pr 的构建过于频繁而禁用
        # synchronize, # 在 pr 者 push commit 时每次构建
        ready_for_review, # draft PR 转为正式 PR
        review_requested,
        reopened,
      ]
    paths:
      - "src/**"
      - "lib/**"

jobs:
  test-on-ubuntu:
    name: 在Ubuntu上测试
    runs-on: ubuntu-latest
    if: github.event.pull_request.base.ref == 'dev'

    steps:
      - name: 检出代码
        uses: actions/checkout@v6

      - name: 测试构建情况
        run: |
          make

      - name: 测试test情况
        run: |
          make test

  test-on-windows:
    name: 在Windows上测试
    runs-on: windows-latest
    if: github.event.pull_request.base.ref == 'dev'

    steps:
      - name: 检出代码
        uses: actions/checkout@v6

      - name: 创建测试文件
        shell: powershell
        run: |
          New-Item -Path "$env:USERPROFILE\Documents\Powershell\Microsoft.PowerShell_profile.ps1" -ItemType File -Force
          New-Item -Path "$env:USERPROFILE\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1" -ItemType File -Force

      - name: 安装依赖
        run: |
          choco install just

      - name: 测试构建情况
        run: |
          just

      - name: 测试test情况
        run: |
          just test


================================================
FILE: .github/workflows/build-on-Linux-AArch64.yml
================================================
# ---------------------------------------------------------------
# Workflow File : build-on-Linux-AArch64.yml
# File Authors  : 曾奥然 <ccmywish@qq.com>
# Contributors  : Nul None <nul@none.org>
#               |
# Created On    : <2023-09-14>
# Last Modified : <2025-09-12>
#
# Build chsrc on Linux (AArch64) and upload it to GitHub: the 'pre' release
# ---------------------------------------------------------------

name: 构建于 Linux AArch64
on:
  push:
    branches: [ "gh-build" ]

jobs:
  build-and-upload:
    runs-on: ubuntu-latest
    steps:
      - name: 构建
        uses: uraimo/run-on-arch-action@v3
        with:
          arch: aarch64
          distro: ubuntu_latest

          dockerRunArgs: |
            --volume "${PWD}/artifacts:/artifacts"
          run: |
            apt-get update -qq
            apt-get install build-essential -y -q
            apt-get install git -y -q
            pwd ; ls -al
            git clone https://github.com/RubyMetric/chsrc -b gh-build -q
            cd chsrc

            make build-in-ci-release-mode
            mv chsrc-ci-release chsrc-aarch64-linux

            cp ./chsrc-aarch64-linux /artifacts

      - name: 上传至 'pre' release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: pre
          files: |
            ./artifacts/chsrc-aarch64-linux


================================================
FILE: .github/workflows/build-on-Linux-ARMv7.yml
================================================
# ---------------------------------------------------------------
# Workflow File : build-on-Linux-ARMv7.yml
# File Authors  : 曾奥然 <ccmywish@qq.com>
# Contributors  : Nul None <nul@none.org>
#               |
# Created On    : <2023-09-14>
# Last Modified : <2025-09-12>
#
# Build chsrc on Linux (ARMv7) and upload it to GitHub: the 'pre' release
# ---------------------------------------------------------------

name: 构建于 Linux ARMv7
on:
  push:
    branches: [ "gh-build" ]

jobs:
  build-and-upload:
    runs-on: ubuntu-latest
    steps:
      - name: 构建
        uses: uraimo/run-on-arch-action@v3
        with:
          arch: armv7
          distro: ubuntu_latest

          dockerRunArgs: |
            --volume "${PWD}/artifacts:/artifacts"
          run: |
            apt-get update -qq
            apt-get install build-essential -y -q
            apt-get install git -y -q
            pwd ; ls -al
            git clone https://github.com/RubyMetric/chsrc -b gh-build -q
            cd chsrc

            make build-in-ci-release-mode
            mv chsrc-ci-release chsrc-armv7-linux

            cp ./chsrc-armv7-linux /artifacts

      - name: 上传至 'pre' release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: pre
          files: |
            ./artifacts/chsrc-armv7-linux


================================================
FILE: .github/workflows/build-on-Linux-riscv64.yml
================================================
# ---------------------------------------------------------------
# Workflow File : build-on-Linux-riscv64.yml
# File Authors  : 曾奥然 <ccmywish@qq.com>
# Contributors  : Nul None <nul@none.org>
#               |
# Created On    : <2023-09-14>
# Last Modified : <2025-09-12>
#
# Build chsrc on Linux (riscv64) and upload it to GitHub: the 'pre' release
# ---------------------------------------------------------------

name: 构建于 Linux riscv64
on:
  push:
    branches: [ "gh-build" ]

jobs:
  build-and-upload:
    runs-on: ubuntu-latest
    steps:
      - name: 构建
        uses: uraimo/run-on-arch-action@v3
        with:
          arch: riscv64
          distro: ubuntu_latest

          dockerRunArgs: |
            --volume "${PWD}/artifacts:/artifacts"
          run: |
            apt-get update -qq
            apt-get install build-essential -y -q
            apt-get install git -y -q
            pwd ; ls -al
            git clone https://github.com/RubyMetric/chsrc -b gh-build -q
            cd chsrc

            make build-in-ci-release-mode
            mv chsrc-ci-release chsrc-riscv64-linux

            cp ./chsrc-riscv64-linux /artifacts

      - name: 上传至 'pre' release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: pre
          files: |
            ./artifacts/chsrc-riscv64-linux


================================================
FILE: .github/workflows/build-on-Linux-x64.yml
================================================
# ---------------------------------------------------------------
# Workflow File : build-on-Linux-x64.yml
# File Authors  : 曾奥然 <ccmywish@qq.com>
# Contributors  : Nul None <nul@none.org>
#               |
# Created On    : <2023-09-14>
# Last Modified : <2025-09-12>
#
# Build chsrc on Linux (x64) and upload it to GitHub: the 'pre' release
# ---------------------------------------------------------------

name: 构建于 Linux x64
on:
  push:
    branches: [ "gh-build" ]

jobs:
  build-and-upload:
    runs-on: ubuntu-latest

    steps:
    - name: 检出代码
      uses: actions/checkout@v6

    - name: 构建
      run: |
        make build-in-ci-release-mode
        mv chsrc-ci-release chsrc-x64-linux

    - name: List files
      run: ls *-linux

    - name: 上传至 'pre' release
      uses: softprops/action-gh-release@v2
      # if: startsWith(github.ref, 'refs/tags/')
      with:
        tag_name: pre
        files: |
          chsrc-x64-linux


================================================
FILE: .github/workflows/build-on-Windows.yml
================================================
# ---------------------------------------------------------------
# Workflow File : build-on-Windows.yml
# File Authors  : 曾奥然 <ccmywish@qq.com>
# Contributors  : Nul None <nul@none.org>
#               |
# Created On    : <2023-09-14>
# Last Modified : <2025-09-12>
#
# Build chsrc on Windows and upload it to GitHub: the 'pre' release
# ---------------------------------------------------------------

name: 构建于 Windows
on:
  push:
    branches: [ "gh-build" ]

jobs:
  build-and-upload:
    runs-on: windows-latest
    defaults:
      run:
        shell: msys2 {0}

    steps:

    - name: 检出代码
      uses: actions/checkout@v6

    - name: 安装 GCC
      uses: msys2/setup-msys2@v2
      with:
        msystem: UCRT64
        update: true
        install: |
          mingw-w64-ucrt-x86_64-gcc
          mingw-w64-ucrt-x86_64-make
          mingw-w64-i686-gcc
          mingw-w64-i686-make

    - name: 为 x64 构建
      run: |
        mingw32-make.exe build-in-ci-release-mode
        mv chsrc-ci-release.exe chsrc-x64-windows.exe

    - name: 为 x32 构建
      env:
        MSYSTEM: MINGW32
      run: |
        mingw32-make.exe build-in-ci-release-mode
        mv chsrc-ci-release.exe chsrc-x86-windows.exe

    - name: 为 Android 构建
      run: |
        compiler=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android21-clang

        # 检查编译器版本
        $compiler --version
        echo

        mingw32-make.exe build-in-ci-release-mode CC=$compiler CROSS_BUILD_WINDOWS_FOR_ANDROID=1
        echo

        # 让我们看看里面有啥
        ls
        echo

        mv chsrc-ci-release chsrc-arm64-android

    - name: List files
      run: ls *.exe

    - name: 上传至 'pre' release
      uses: softprops/action-gh-release@v2
      # if: startsWith(github.ref, 'refs/tags/')
      with:
        tag_name: pre
        files: |
          chsrc-x64-windows.exe
          chsrc-x86-windows.exe
          chsrc-arm64-android


================================================
FILE: .github/workflows/build-on-macOS.yml
================================================
# ---------------------------------------------------------------
# Workflow File : build-on-macOS.yml
# File Authors  : 曾奥然 <ccmywish@qq.com>
# Contributors  : Nul None <nul@none.org>
#               |
# Created On    : <2023-09-15>
# Last Modified : <2025-12-18>
#
# Build chsrc on macOS and upload it to GitHub: the 'pre' release
# ---------------------------------------------------------------

name: 构建于 macOS
on:
  push:
    branches: [ "gh-build" ]

jobs:
  on-arm64:
    runs-on: macos-latest

    steps:
    - name: 检出代码
      uses: actions/checkout@v6

    - name: 检查编译器版本
      run: |
        clang --version
        echo
        gcc --version
        echo
        gcc-14 --version

    - name: 为 arm64 (AArch64) 构建
      run: |
        make build-in-ci-release-mode
        mv chsrc-ci-release chsrc-aarch64-macos

    - name: List files
      run: ls *-macos

    - name: 上传至 'pre' release
      uses: softprops/action-gh-release@v2
      # if: startsWith(github.ref, 'refs/tags/')
      with:
        tag_name: pre
        files: |
          chsrc-aarch64-macos


  on-x64:
    # macos-13 是 x64,macos-14 是 AArch64(ARMv8-A)
    # 但是 macos-13 已经于 2025-12-04 下线
    runs-on: macos-15-intel

    steps:
    - name: 检出代码
      uses: actions/checkout@v6

    - name: 检查编译器版本
      run: |
        clang --version
        echo
        gcc --version
        echo
        gcc-14 --version

    - name: 为 x64 构建
      run: |
        make build-in-ci-release-mode
        mv chsrc-ci-release chsrc-x64-macos

    - name: List files
      run: ls *-macos

    - name: 上传至 'pre' release
      uses: softprops/action-gh-release@v2
      # if: startsWith(github.ref, 'refs/tags/')
      with:
        tag_name: pre
        files: |
          chsrc-x64-macos


================================================
FILE: .github/workflows/pkg-deb.yml
================================================
# ---------------------------------------------------------------
# Workflow File : pkg-deb.yml
# File Authors  : sanchuanhehe <wyihe5520@gmail.com>
# Contributors  : 曾奥然 <ccmywish@qq.com>
#               |
# Created On    : <2025-06-10>
# Last Modified : <2025-10-29>
#
# Build and publish deb packages
# ---------------------------------------------------------------

name: 构建发布deb包

on:
  release:
    types: [ released ]
  push:
    branches: [ "gh-build" ]
  workflow_dispatch:
    inputs:
      version:
        description: 'Version to build'
        required: true
        default: '0.3.0'  # 短暂时间内不可达到的最新版本号

jobs:
  Build-deb:
    name: 构建deb包
    runs-on: ubuntu-latest

    steps:
    - name: 检出代码
      uses: actions/checkout@v6
      with:
        ref: gh-build

    - name: 获取版本号
      id: get_version
      run: |
        if [ "${{ github.event_name }}" = "release" ]; then
          version="${{ github.event.release.tag_name }}"
          # 删除前缀 'v' if present
          version=${version#v}

        elif [ "${{ github.event_name }}" = "push" ];then
          # 从源代码中提取版本号
          version=$(sed -E -n 's/^#define Chsrc_Version +"([0-9]+\.[0-9]+\.[0-9]+).*"/\1/p' ./src/framework/version.h)

        else
          version="${{ github.event.inputs.version }}"
        fi

        echo "version=$version" >> $GITHUB_OUTPUT
        echo "Version: $version"

    - name: 验证版本号
      run: |
        version="${{ steps.get_version.outputs.version }}"

        if [[ ! $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
          echo "Invalid version format: $version"
          exit 1
        fi

    - name: 更新 debian/changelog
      run: |
        version="${{ steps.get_version.outputs.version }}"

        cd ./pkg/deb

        (cat << EOF; cat ./debian/changelog) > new_changelog
        chsrc ($version-1) unstable; urgency=medium

          * Release version $version

         -- 曾奥然 <ccmywish@qq.com>  $(date -R)

        EOF

        mv -f new_changelog ./debian/changelog

    - name: 安装构建依赖
      run: |
        sudo apt-get update
        sudo apt-get install -y debhelper devscripts build-essential fakeroot

    - name: 构建
      run: |
        make build-deb

    - name: 移动构建产物到./dist和./dist-for-pre
      run: |
        version="${{ steps.get_version.outputs.version }}"

        # 创建两个目录来存放构建产物(产物内容一样,只是文件名不一样)
        mkdir dist dist-for-pre
        find ./pkg -name "chsrc_${version}*.deb" -exec mv {} dist/ \;
        cp -r dist/* dist-for-pre/

        # 上传至 'pre' release 的文件名需要设置为 'latest', 从而稳定下载URL
        cd ./dist-for-pre
        for old_name in ./chsrc_${version}*.deb; do
          new_name="${old_name/${version}-1/latest-1}"
          mv "$old_name" "$new_name"
        done

    - name: 验证生成的deb包
      run: |
        version="${{ steps.get_version.outputs.version }}"
        ls -la dist/
        dpkg-deb --info dist/chsrc_${version}-1_amd64.deb
        dpkg-deb --contents dist/chsrc_${version}-1_amd64.deb

    - name: 测试deb包能否正常安装
      run: |
        version="${{ steps.get_version.outputs.version }}"

        sudo dpkg -i dist/chsrc_${version}-1_amd64.deb || true
        sudo apt-get install -f -y || true

        bash pkg/deb/deb-installation-test.sh

    - name: 上传deb包到artifacts
      uses: actions/upload-artifact@v6
      with:
        name: chsrc-deb-files
        path: dist/chsrc_*.deb
        retention-days: 30

    - name: 上传附件到GitHub Releases(the newly created release)
      if: github.event_name == 'release'
      uses: softprops/action-gh-release@v2
      with:
        # 用 * 省略版本号,以及指代各种架构
        files: dist/chsrc_*.deb

    - name: 上传附件到GitHub Releases(the 'pre' release)
      if: github.event_name == 'push'
      uses: softprops/action-gh-release@v2
      with:
        tag_name: pre
        # 用 * 指代各种架构
        files: dist-for-pre/chsrc_latest-1_*.deb





  Create-APT-repository:
    name: 创建APT仓库
    needs: Build-deb
    runs-on: ubuntu-latest
    if: github.event_name == 'release'

    steps:
    - name: Download all artifacts
      uses: actions/download-artifact@v7
      with:
        pattern: chsrc-deb-files
        merge-multiple: true
        path: ./debs

    - name: Install repository tools
      run: |
        sudo apt-get update
        sudo apt-get install -y dpkg-dev

    - name: Create Packages file
      run: |
        cd debs
        dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz
        dpkg-scanpackages . /dev/null > Packages

    - name: Upload repository metadata
      uses: actions/upload-artifact@v6
      with:
        name: debian-repository-metadata
        path: debs/Packages*
        retention-days: 30


================================================
FILE: .github/workflows/pub-AUR-chsrc-and-chsrc-bin.yml
================================================
# ---------------------------------------------------------------
# Workflow File : pub-AUR-chsrc-and-chsrc-bin.yml
# File Authors  : Terrasse <terrasse@qq.com>
# Contributors  : Nul None <nul@none.org>
#               |
# Created On    : <2024-08-29>
# Last Modified : <2025-03-18>
#
# Publish the 2 packages to AUR when a new release is created:
#   1. chsrc
#   2. chsrc-bin
#
# Note: only normal version tags like 'v1.2.3' will be published
# ---------------------------------------------------------------

name: Publish 'chsrc' and 'chsrc-bin' to AUR
on:
  release:
    types: [ released ]

jobs:
  publish:
    runs-on: ubuntu-latest

    steps:
    - name: Get the release tag
      id: get_tag
      run: |
        echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
    - name: Validate version tag
      run: |
        if [[ ! $tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
          echo "Abnormal version tag: $tag"
          echo "valid=0" >> $GITHUB_ENV
        else
          version=$(echo $tag | sed 's/^v//')
          echo "version=$version" >> $GITHUB_ENV
          echo "valid=1" >> $GITHUB_ENV
        fi
    - name: Fetch PKGBUILD
      run: |
        wget https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD\?h\=chsrc-bin -O ./PKGBUILD_bin
    - name: Update PKGBUILD
      run: |
        sed -i "s/pkgver=.*/pkgver=$version/" PKGBUILD_bin
    - name: Publish chsrc-bin to AUR
      if: env.valid == '1'
      uses: KSXGitHub/github-actions-deploy-aur@v4.1.1
      with:
        pkgname: chsrc-bin
        pkgbuild: ./PKGBUILD_bin
        updpkgsums: true
        test: true # Check that PKGBUILD could be built, and update pkgver
        commit_username: ${{ secrets.AUR_USERNAME }}
        commit_email: ${{ secrets.AUR_EMAIL }}
        ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
        commit_message: "github-action-auto-publish v${{ env.version }}"
    - name: Fetch PKGBUILD
      run: |
        wget https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD\?h\=chsrc -O ./PKGBUILD
    - name: Update PKGBUILD
      run: |
        sed -i "s/pkgver=.*/pkgver=$version/" PKGBUILD
    - name: Publish chsrc to AUR
      if: env.valid == '1'
      uses: KSXGitHub/github-actions-deploy-aur@v4.1.1
      with:
        pkgname: chsrc
        pkgbuild: ./PKGBUILD
        updpkgsums: true
        test: true # Check that PKGBUILD could be built, and update pkgver
        commit_username: ${{ secrets.AUR_USERNAME }}
        commit_email: ${{ secrets.AUR_EMAIL }}
        ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
        commit_message: "github-action-auto-publish v${{ env.version }}"


================================================
FILE: .github/workflows/pub-AUR-chsrc-git.yml
================================================
# ---------------------------------------------------------------
# Workflow File : pub-AUR-chsrc-git.yml
# File Authors  : Terrasse <terrasse@qq.com>
# Contributors  : Nul None <nul@none.org>
#               |
# Created On    : <2024-08-29>
# Last Modified : <2025-06-19>
#
# Publish package 'chsrc-git' to AUR when branch 'main' is updated.
# ---------------------------------------------------------------

name: Publish 'chsrc-git' to AUR
on:
  workflow_dispatch:
  push:
    branches: [ "main" ] # chsrc-git syncs with main
    paths:
      - "src/**"
      - "lib/**"

jobs:
  publish:
    runs-on: ubuntu-latest

    steps:
    - name: Fetch PKGBUILD
      run: |
        wget https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD\?h\=chsrc-git -O ./PKGBUILD
    - name: Publish to AUR
      uses: KSXGitHub/github-actions-deploy-aur@v4.1.1
      with:
        pkgname: chsrc-git
        pkgbuild: ./PKGBUILD
        test: true # Check that PKGBUILD could be built, and update pkgver
        commit_username: ${{ secrets.AUR_USERNAME }}
        commit_email: ${{ secrets.AUR_EMAIL }}
        ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
        commit_message: "github-action-auto-publish\n${{ github.sha }}"


================================================
FILE: .github/workflows/pub-WinGet.yml
================================================
# ---------------------------------------------------------------
# Workflow File : pub-WinGet.yml
# File Authors  :   YU-7   <2747046473@qq.com>
# Contributors  : Nul None <nul@none.org>
#               |
# Created On    : <2024-12-25>
# Last Modified : <2024-12-25>
#
# This workflow publish to winget
# ---------------------------------------------------------------

name: Publish to WinGet
on:
  release:
    types: [released]
jobs:
  publish:
    runs-on: windows-latest
    steps:
      - uses: vedantmgoyal9/winget-releaser@main
        with:
          identifier:  RubyMetric.chsrc
          installers-regex: '\.exe$' # Only .exe files
          token: ${{ secrets.WINGET_TOKEN }}


================================================
FILE: .gitignore
================================================
##############################
#          VS Code
##############################
.vscode/*
!.vscode/extensions.json
!.vscode/settings.json
!.vscode/c_cpp_properties.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/README.md


##############################
#            VS
##############################
.vs


##############################
#         Binaries
##############################
*.o
*.obj
*.a
*.lib
*.so
*.dll
*.out
*.exe
*.res


##############################
#      Built executables
##############################
chsrc
chsrc-debug
chsrc-release
chsrc-ci-release



##############################
#        Test files
##############################
xy
fw
README.md.bak*
*.tmp
chsrc_tmp_test.txt
chsrc_tmp_test.txt.bak

# Generated when testing (when there's a bug)
nul

# 'chsrc set -scope=project' generated
.bundle
.npmrc



##############################
#          Texinfo
##############################
chsrc.aux
chsrc.log
chsrc.toc
*.info
*.pdf



##############################
#         deb package
##############################
# deb package 未归档的目录
pkg/deb/debian/chsrc/

# 下面这个目录包含创建出 $HOME 的虚拟环境
pkg/deb/debian/.debhelper/

pkg/deb/debian/debhelper-build-stamp
pkg/deb/debian/files
pkg/deb/debian/chsrc.debhelper.log
pkg/deb/debian/chsrc.substvars

# 以下为 deb package 构建的直接产物
chsrc_*.deb
chsrc-dbgsym_*.ddeb
chsrc_*.build
chsrc_*.buildinfo
chsrc_*.changes


================================================
FILE: .vscode/README.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : (for VS Code users) README.md
 ! Doc Authors   : 曾奥然 <ccmywish@qq.com>
 ! Contributors  : Nul None <nul@none.org>
 !               |
 ! Created On    : <2025-06-18>
 ! Last Modified : <2025-06-20>
 ! ---------------------------------------------------------- -->

# Dev in VS Code

首先需要安装好 [just](https://github.com/casey/just),而不再硬性需要 `make`

1. `Ctrl-Shift-B` 直接构建
2. `F5` 直接开始 Debug


================================================
FILE: .vscode/c_cpp_properties.json
================================================
{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "cStandard": "c17",
            "intelliSenseMode": "windows-gcc-x64"
        },
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "cStandard": "c17"
        },
        {
            "name": "Mac",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "cStandard": "c17"
        }
    ],
    "enableConfigurationSquiggles": true,
    "version": 4
}


================================================
FILE: .vscode/extensions.json
================================================
{
    "recommendations": [
        "ms-vscode.cpptools",
        "ms-vscode.cpptools-extension-pack",
        "editorconfig.editorconfig",
        "redhat.vscode-yaml",
        "nefrob.vscode-just-syntax"
    ],
    "unwantedRecommendations": [
        "esbenp.prettier-vscode"
    ]
}


================================================
FILE: .vscode/launch.json
================================================
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug chsrc",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/chsrc-debug",
            "args": [
                "get",
                "nodejs"
            ],
            "preLaunchTask": "构建 debug 版 chsrc",
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            // 如果你认为使用弹出窗口难以调试,可尝试设置为false
            "externalConsole": true,
            // lldb 等请自行设置,不作额外说明
            "MIMode": "gdb",
            // "miDebuggerPath": "/path/to/gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description": "Set Disassembly Flavor to Intel",
                    "text": "-gdb-set disassembly-flavor intel",
                    "ignoreFailures": true
                }
            ],
            "postDebugTask": "停止 debug 程序"
        },

        {
            "name": "Debug framework",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/fw",
            "args": [],
            "preLaunchTask": "测试 framework",
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            // "miDebuggerPath": "/path/to/gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description": "Set Disassembly Flavor to Intel",
                    "text": "-gdb-set disassembly-flavor intel",
                    "ignoreFailures": true
                }
            ]
        }
    ]
}

================================================
FILE: .vscode/settings.json
================================================
{
    "editor.fontLigatures": false,

    "C_Cpp.autoAddFileAssociations": false,
    "C_Cpp.intelliSenseEngine": "Tag Parser",
    "C_Cpp.default.browse.limitSymbolsToIncludedHeaders": false,

    "editor.formatOnSave": false,

    "C_Cpp.clang_format_fallbackStyle": "GNU",
    "C_Cpp.formatting": "disabled",

    "[c]": {
        "editor.defaultFormatter": null,
    },
    "[h]": {
        "editor.defaultFormatter": null
    },
    "[jsonc]": {
        "editor.defaultFormatter": "vscode.json-language-features"
    },
    "[yaml]": {
        "editor.defaultFormatter": "redhat.vscode-yaml"
    },

    "vscode-just.formatOnSave": false,
}


================================================
FILE: .vscode/tasks.json
================================================
{
    "tasks": [
        {
            "type": "shell",
            "label": "构建 chsrc",
            "command": "just",
            "args": [
                "build"
            ],
            "options": {
                "cwd": "${workspaceFolder}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "dependsOn": "停止程序",
            "detail": "先停止原有程序,然后使用 just build 编译"
        },
        {
            "type": "shell",
            "label": "构建 debug 版 chsrc",
            "command": "just",
            "args": [
                "build-in-debug-mode"
            ],
            "options": {
                "cwd": "${workspaceFolder}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": false
            },
        },
        {
            "type": "shell",
            "label": "测试 chsrc",
            "command": "just",
            "args": [
                "test"
            ],
            "options": {
                "cwd": "${workspaceFolder}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "test",
                "isDefault": true
            },
            "detail": "使用 just test 测试"
        },
        {
            "type": "shell",
            "label": "测试 framework",
            "command": "just",
            "args": [
                "test-fw"
            ],
            "options": {
                "cwd": "${workspaceFolder}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "test",
                "isDefault": false
            },
            "detail": "使用 just test-fw 测试 framework"
        },
        {
            "type": "shell",
            "label": "测试 xy.h",
            "command": "just",
            "args": [
                "test-xy"
            ],
            "options": {
                "cwd": "${workspaceFolder}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "test",
                "isDefault": false
            },
            "detail": "使用 just test-xy 测试 xy.h"
        },
        {
            "type": "shell",
            "label": "停止 debug 程序",
            "windows": {
                "command": "powershell",
                "args": [
                    "-c",
                    "Get-Process -Name \"chsrc-debug\" -ErrorAction SilentlyContinue | Stop-Process -Force;",
                    "Get-Process -Name \"gdb\" -ErrorAction SilentlyContinue | Stop-Process -Force;",
                    "Get-Process -Name \"WindowsDebugLauncher\" -ErrorAction SilentlyContinue | Stop-Process -Force;"
                ]
            },
            "linux": {
                "command": "bash",
                "args": [
                    "-c",
                    "if pgrep -f chsrc-debug > /dev/null; then pkill -f chsrc-debug; fi"
                ]
            },
            "osx": {
                "command": "bash",
                "args": [
                    "-c",
                    "if pgrep -f chsrc-debug > /dev/null; then pkill -f chsrc-debug; fi"
                ]
            },
            "group": "build",
            "presentation": {
                "echo": true,
                "reveal": "silent",
                "focus": false,
                "panel": "shared",
                "showReuseMessage": true,
                "clear": false
            },
            "detail": "停止 debug 版本的 chsrc"
        },
        {
            "type": "shell",
            "label": "停止程序",
            "windows": {
                "command": "powershell",
                "args": [
                    "-c",
                    "Get-Process -Name \"chsrc\" -ErrorAction SilentlyContinue | Stop-Process -Force;"
                ]
            },
            "linux": {
                "command": "bash",
                "args": [
                    "-c",
                    "if pgrep -f chsrc > /dev/null; then pkill -f chsrc; fi"
                ]
            },
            "osx": {
                "command": "bash",
                "args": [
                    "-c",
                    "if pgrep -f chsrc > /dev/null; then pkill -f chsrc; fi"
                ]
            },
            "group": "build",
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "shared",
                "showReuseMessage": true,
                "clear": false
            },
            "detail": "跨平台停止 chsrc"
        }
    ],
    "version": "2.0.0"
}

================================================
FILE: COPYING
================================================
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.


================================================
FILE: LICENSE-MIT.txt
================================================
MIT License

Copyright (c) 2023-2026 曾奥然 (Aoran Zeng), 郭恒 (Heng Guo)

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:

The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.

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.


================================================
FILE: Makefile
================================================
#!/usr/bin/make -f
# --------------------------------------------------------------
# SPDX-License-Identifier: GPL-3.0-or-later
# --------------------------------------------------------------
# Build File    : Makefile
# File Authors  : 曾奥然 <ccmywish@qq.com>
# Contributors  : Yangmoooo <yangmoooo@outlook.com>
#								| sanchuanhehe <wyihe5520@gmail.com>
#								|
# Created On    : <2023-08-28>
# Last Modified : <2025-10-15>
#
# 请阅读 ./doc/01-开发与构建.md 来使用
# --------------------------------------------------------------

#=========== OS Check ================
On-Linux = 0
On-Windows = 0
On-macOS = 0

ifeq ($(shell uname), Linux)
	On-Linux = 1
endif

ifeq ($(shell uname), Darwin)
	On-macOS = 1
endif

# 只有 MSYS2 会定义 $(OS) 变量
ifeq ($(OS), Windows_NT)
	On-Windows = 1
endif
# 注意, 原生 Windows 会定义 $(ComSpec) 变量,且区分大小写
# 但是 MSYS2 并不会定义
#=====================================



#======== Default Tooling ============
ifeq ($(On-Windows), 1)
  # MSYS2 环境
	CC = cc
else ifeq ($(On-macOS), 1)
	CC = clang
else
	CC = cc
endif

ifeq ($(On-macOS), 1)
	DEBUGGER = lldb
else
	DEBUGGER = gdb
endif
#=====================================



#======== Compilation Config ==========
CFLAGS += -Iinclude -Ilib

ifeq ($(On-Windows), 1)
	CLANG_FLAGS = -target x86_64-pc-windows-gnu
endif

ifeq ($(CC), clang)
	CFLAGS += $(CLANG_FLAGS)
endif

override WARN += -Wall -Wextra -Wno-unused-variable -Wno-unused-function -Wno-missing-braces -Wno-misleading-indentation \
	-Wno-missing-field-initializers -Wno-unused-parameter -Wno-sign-compare
_C_Warning_Flags := $(WARN)

DevMode-Target-Name = chsrc
DebugMode-Target-Name = chsrc-debug
ReleaseMode-Target-Name = chsrc-release
CIReleaseMode-Target-Name = chsrc-ci-release

CFLAGS_debug  = -g -DXY_DEBUG
CFLAGS_static = -static
CFLAGS_optimization = -O2

ifdef DEBUG
	CFLAGS += $(CFLAGS_debug)
endif

STATIC = 0

ifeq ($(STATIC), 1)
	CFLAGS += $(CFLAGS_static)
endif
#=====================================



#====== CI release mode 的配置 =======
ifeq ($(MAKECMDGOALS), build-in-ci-release-mode)

	CFLAGS += $(CFLAGS_optimization)

  # 仅在 Linux 上使用静态链接
	ifeq ($(On-Linux), 1)
		CFLAGS += $(CFLAGS_static)
	endif

  # GitHub Actions 上的 macOS 中的 LLVM 太老了
  # 而且 gcc 被重命名为了 clang
  # 需要直接指定版本
  ifeq ($(On-macOS), 1)
    CC = gcc-14
  endif

endif
#=====================================



#============ Aliases ================
all: build

b: build-in-dev-mode
build: build-in-dev-mode
bd: build-in-debug-mode
br: build-in-release-mode
bcir: build-in-ci-release-mode
d: debug
t: test
check: test
c: clean
#=====================================



build-in-dev-mode:
	@echo Starting: Build in DEV mode: \'$(CC)\' $(CFLAGS) -o $(DevMode-Target-Name)
	@$(CC) src/chsrc-main.c $(CFLAGS) $(_C_Warning_Flags) -o $(DevMode-Target-Name)
	@echo Finished: Build in DEV mode

build-in-debug-mode: CFLAGS += $(CFLAGS_debug)
build-in-debug-mode:
	@echo Starting: Build in DEBUG mode: \'$(CC)\' $(CFLAGS) -o $(DebugMode-Target-Name)
	@$(CC) src/chsrc-main.c $(CFLAGS) $(_C_Warning_Flags) -o $(DebugMode-Target-Name)
	@echo Finished: Build in DEBUG mode

build-in-release-mode: CFLAGS += $(CFLAGS_optimization)
build-in-release-mode:
	@echo Starting: Build in RELEASE mode: \'$(CC)\' $(CFLAGS) -o $(ReleaseMode-Target-Name)
	@$(CC) src/chsrc-main.c $(CFLAGS) $(_C_Warning_Flags) -o $(ReleaseMode-Target-Name)
	@echo Finished: Build in RELEASE mode

# CI release mode 的配置在该文件上方
build-in-ci-release-mode:
	@echo Starting: Build in CI-RELEASE mode: \'$(CC)\' $(CFLAGS) -o $(CIReleaseMode-Target-Name)
	@$(CC) src/chsrc-main.c $(CFLAGS) $(_C_Warning_Flags) -o $(CIReleaseMode-Target-Name)
	@echo Finished: Build in CI-RELEASE mode

# 永远重新编译
debug: build-in-debug-mode
	@$(DEBUGGER) $(DebugMode-Target-Name)

test: test-make-env test-xy test-fw

test-make-env:
	@echo "On-Linux: $(On-Linux)"
	@echo "On-Windows: $(On-Windows)"
	@echo "On-macOS: $(On-macOS)"
	@echo "CC: $(CC)"
	@echo "CFLAGS: $(CFLAGS)"
	@echo "USER: $$(whoami)"
	@echo "PWD: $(shell pwd)"
	@echo "UID: $$(id -u)"
	@echo "GID: $$(id -g)"
# 检查HOME环境变量
	@if [ -z "$(HOME)" ]; then \
	 echo "HOME environment variable is not set!"; \
	else \
	 echo "HOME: $(HOME)"; \
	fi

# 这两个测试文件都用 DEBUG mode
test-xy: CFLAGS += $(CFLAGS_debug)
test-xy:
	@$(CC) test/xy.c $(CFLAGS) -o xy
	@./xy

test-fw: CFLAGS += $(CFLAGS_debug)
test-fw:
	@$(CC) test/fw.c $(CFLAGS) -o fw
	@./fw

check: test

# AUR package 安装时将执行此 target
fastcheck: $(DevMode-Target-Name)
	@perl ./test/cli.pl fastcheck

test-cli: $(DevMode-Target-Name)
	@perl ./test/cli.pl

clean:
	-@rm *.exe  2>/dev/null
	-@rm *.res  2>/dev/null
	-@rm xy     2>/dev/null
	-@rm fw     2>/dev/null
	-@rm README.md.bak*    2>/dev/null

	-@rm chsrc  					 2>/dev/null
	-@rm chsrc-debug       2>/dev/null
	-@rm chsrc-release  	 2>/dev/null
	-@rm chsrc-ci-release  2>/dev/null

# -include pkg/deb/Makefile # 不这么做,因为 pkg/deb/Makefile 需要在 pkg/deb 目录下执行
# 保持动词在前的任务名风格
build-deb:
	@$(MAKE) -C pkg/deb deb-build

clean-deb:
	@$(MAKE) -C pkg/deb deb-clean

install: $(ReleaseMode-Target-Name)
	install -D -m 755 $(ReleaseMode-Target-Name) $(DESTDIR)/usr/bin/chsrc
	install -D -m 644 doc/chsrc.1 $(DESTDIR)/usr/share/man/man1/chsrc.1

# 这样还是太麻烦,不用,我们还是靠 just 来调用吧
#
# 通过 make rawstr4c ARGS="[--debug] Markdown.md" 来调用
#rawstr4c:
#	@bash ./tool/rawstr4c/run/run.sh $(ARGS)

.PHONY: all b build bd br bcir d t check c \
	build-in-dev-mode build-in-debug-mode build-in-release-mode build-in-ci-release-mode \
	debug test test-make-env test-xy test-fw fastcheck test-cli clean install build-deb clean-deb rawstr4c


================================================
FILE: README.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : README.md
 ! Doc Authors   : 曾奥然 <ccmywish@qq.com>
 ! Contributors  : Mikachu2333 <mikachu.23333@zohomail.com>
 !               | BingChunMoLi <bingchunmoli@bingchunmoli.com>
 !               |
 ! Created On    : <2023-12-28>
 ! Last Modified : <2026-02-24>
 ! ---------------------------------------------------------- -->

<div align="center">
  <img alt="chsrc logo" src="doc/image/chsrc.png"/>
</div>

全平台通用换源工具与框架 `chsrc`,**目标支持 Linux, Windows (native, MSYS2, Cygwin), macOS, BSD, Android 等尽可能多的操作系统环境,龙芯、飞腾、RISC-V 等尽可能多的 CPU**。

我们使用 **C11** 来完成上述目标。我们并不使用 Python 或 JavaScript 等解释语言,因为一个简单的换源工具,不应该强行塞给用户一个庞大的解释器和数十、数百 MB 其他文件。

本软件为**自由软件**,SDPX 软件许可证为 `GPL-3.0-or-later and MIT`

<br>



<table align="center">
  <tr>
  <td>
    <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>
  </td>
  <td>
    <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>
  </td>
  </tr>
</table>

<br>



## ❤️ 致所有的朋友们

2025年8月11日,我因通宵重构本项目代码而被送去抢救([#252](https://github.com/RubyMetric/chsrc/issues/252),[突发!换源工具 chsrc 作者在重构过程中被送去 120 抢救](https://v2ex.com/t/1151802))。大家给予的关心和帮助让我非常非常感动!在此,我衷心感谢每一位朋友!**无论是开源还是闭源,无论是否为职业程序员,我们其实都是一群使用软件、热心互助、充满友爱的人,这是一个温暖的大家庭**。

我为 `chsrc` 采用 GPL 协议,怀着殷切的期望:**希望能够营造像 Richard Stallman 在创建 GNU 项目之前,在 MIT 那样的氛围——写自己用得上的软件,与大家一起开发、维护,简单纯粹,无关商业利益。就像小区、校园自发组建的足球篮球队,从一次偶然的加入,逐渐成长为互相支持的伙伴**。

这次经历让我更加深刻地体会到:开源,是一种把大家联系在一起的方式,**它让友情、互助和协作成为可能,也让我们在共同的目标中建立起长期的纽带**。

最后,希望大家能够**时刻关注**自己的身体,**你可以随时 `chsrc` `chown` `chgrp` `chmod` 无限次,但是无法 `chbody`**!

<br>



## 🤝 协作与贡献

> [!TIP]
> **`chsrc` 不仅是一个命令行工具,同时也是一个体现了 Ruby on Rails 思想的 MVC 换源框架,它甚至使你能够在不了解C语言的情况下编写出新的换源方法 (recipe)。** 配合使用 [rawstr4c], 这将比写 shell 脚本更加轻松。 [如何编写 recipe?](./doc/10-如何编写recipe.md)

---

> [!NOTE]
> 这也许是你可以参与的第一个现实世界中有用的C语言项目,[用 VS Code 一分钟内上手编译、运行、测试 chsrc](./doc/01-开发与构建.md)
>
> 欢迎对 GitHub、Gitee 协作不熟悉的人以此为契机学习参与贡献, 欢迎任何编程初学者。[从开发到提交PR,我们覆盖全流程文档](./doc/)
---

> [!IMPORTANT]
> **`chsrc` 可换源 65+ 目标。每个人仅仅贡献和维护自己熟悉的部分,回报是得到其他所有领域专家的帮助。** [欢迎成为 recipe 维护者](https://github.com/RubyMetric/chsrc/issues/275)

<br>

可参与的任务与挑战:

1. [Shell auto-completion 终端命令自动补全](https://github.com/RubyMetric/chsrc/issues/204)

2. [搜集默认源地址,帮助使用 `reset` 功能](https://github.com/RubyMetric/chsrc/issues/111)

3. [搜集测速地址,进行精准测速](https://github.com/RubyMetric/chsrc/issues/205)

4. [chsrc-bootstrap: 为不存在预编译 `chsrc` 的平台提供支持](https://github.com/RubyMetric/chsrc/issues/230)

<br>

<details>
<summary>已由贡献者完成的挑战</summary>

1. [[Challenge] 编写统一安装的 shell 和 PowerShell 脚本](https://github.com/RubyMetric/chsrc/issues/98)

    已由 [@Efterklang] 与 [@wickdynex] 完成

</details>

<details>
<summary>镜像站可用性</summary>

1. <https://github.com/RubyMetric/chsrc/wiki>
2. <https://github.com/RubyMetric/chsrc/discussions>

</details>

<details>
<summary>打包</summary>

想通过 `dnf`, `flatpak`, `snap` 等系统包管理工具来安装和更新`chsrc`?若可提供维护,请访问 [issue#16 on GitHub](https://github.com/RubyMetric/chsrc/issues/16)

- [x] `Homebrew`
- [x] `Scoop`
- [x] `WinGet`
- [x] `AUR`
- [ ] `Flatpak`
- [ ] `snap`
- [ ] 缺乏其他平台/包维护者

</details>

<br>



## 📌 示例

桌面端:

<div align="center">
  <img alt="chsrc set node" src="doc/image/example-set-nodejs.png"/>
</div>

<br>

安卓:

<div align="center">
  <img alt="chsrc set python and chsrc set termux" src="doc/image/chsrc-on-Android-set-python-and-termux.jpg" width="300" height="750"/>
</div>

<br>



## 🚀 安装

<a href="https://repology.org/project/chsrc/versions">
  <img src="https://repology.org/badge/vertical-allrepos/chsrc.svg" alt="Packaging status" align="right">
</a>

> [!IMPORTANT]
> 若通过下述手动方式安装,则会下载到当前目录,可直接通过 `./chsrc` 运行

<details>
<summary>Windows</summary>

- 可通过 `scoop` 安装,感谢 [@Gn3po4g] 与 [@niheaven]

```bash
scoop install chsrc
```

<br>

- 可通过 `WinGet` 安装,感谢 [@YU-7]

```bash
winget install RubyMetric.chsrc
```

<br>

- 可通过 `PowerShell` 脚本一键下载最新版二进制文件,感谢 [@wickdynex]

    若下方链接无法访问,可使用 `https://gitee.com/RubyMetric/chsrc/raw/main/tool/installer.ps1` 替代

```PowerShell
# 使用 -Version 指定版本 (不指定时默认为 pre)
#   1. 安装 pre 版本; 这比从包管理器安装的总是更新一些
#   2. 安装旧版本; 有时新版本可能引入某些 Bug,临时使用旧版本解决燃眉之急
"& { $(iwr -useb https://chsrc.run/windows) } -Version pre" | iex
```

<br>

- 或手动下载二进制文件,这是最新版,往往比 `scoop` 提供的更新,适用于修复 Bug、添加新功能后及时使用,以及未安装 `scoop` 时

```bash
# x64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x64-windows.exe -o chsrc.exe

# x86
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x86-windows.exe -o chsrc.exe
```

</details>



<details>
<summary>Linux</summary>

- 可通过 `apt`/`dpkg` 安装,感谢 [@sanchuanhehe]

```bash
# x64
$ curl -LO https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc_latest-1_amd64.deb

# 也可以使用 Wget
wget https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc_latest-1_amd64.deb

$ sudo apt install ./chsrc_latest-1_amd64.deb
# 或
$ sudo sudo dpkg -i chsrc_latest-1_amd64.deb
```

<br>

- 支持 `AUR`,可通过 `yay` 安装,感谢 [@Jerry-Terrasse]

```bash
# AUR
$ yay -S chsrc-bin # Binary from GitHub Release
$ yay -S chsrc-git # Build  from the latest main branch (stable)
$ yay -S chsrc     # Build  from GitHub Release
```

<br>

- 可通过 `shell` 脚本一键安装最新版,感谢 [@Efterklang] 与 [@wickdynex]

    若下方链接无法访问,可使用 `https://gitee.com/RubyMetric/chsrc/raw/main/tool/installer.sh` 替代

```bash
# 非root用户默认安装至 ~/.local/bin
$ curl https://chsrc.run/posix | bash

# 也可以使用 Wget
$ wget -O - https://chsrc.run/posix | bash

# root用户默认安装至 /usr/local/bin
$ curl https://chsrc.run/posix | sudo bash

# 使用 -d 指定目录安装
$ curl https://chsrc.run/posix | bash -s -- -d ./

# 使用 -v 指定版本 (不指定时默认为 pre)
#   1. 安装 pre 版本; 这比从包管理器安装的总是更新一些
#   2. 安装旧版本; 有时新版本可能引入某些 Bug,临时使用旧版本解决燃眉之急
$ curl https://chsrc.run/posix | bash -s -- -v 0.2.1

# 使用 -l en 输出英文
$ curl https://chsrc.run/posix | bash -s -- -l en
```

<br>

- 可手动下载二进制文件安装

```bash
# x64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x64-linux -o chsrc; chmod +x ./chsrc

# aarch64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-aarch64-linux -o chsrc; chmod +x ./chsrc

# riscv64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-riscv64-linux -o chsrc; chmod +x ./chsrc

# armv7
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-armv7-linux -o chsrc; chmod +x ./chsrc
```

如果你所在的处理器架构没有预编译版本,可以使用 [chsrc-bootstrap]

</details>



<details>
<summary>macOS</summary>

- 可通过 `homebrew` 安装,感谢 [@Aaron-212] 与 [@chenrui333]

```bash
brew install chsrc
```

<br>

- 可通过 `shell` 脚本安装最新版,感谢 [@Efterklang] 与 [@wickdynex]

    若下方链接无法访问,可使用 `https://gitee.com/RubyMetric/chsrc/raw/main/tool/installer.sh` 替代

```bash
# 非root用户默认安装至 ~/.local/bin
$ curl https://chsrc.run/posix | bash

# root用户默认安装至 /usr/local/bin
$ curl https://chsrc.run/posix | sudo bash

# 使用 -d 指定目录安装
$ curl https://chsrc.run/posix | bash -s -- -d ./

# 使用 -v 指定版本 (不指定时默认为 pre)
#   1. 安装 pre 版本; 这比从包管理器安装的总是更新一些
#   2. 安装旧版本; 有时新版本可能引入某些 Bug,临时使用旧版本解决燃眉之急
$ curl https://chsrc.run/posix | bash -s -- -v 0.2.1

# 使用 -l en 输出英文
$ curl https://chsrc.run/posix | bash -s -- -l en
```

<br>

- 或手动下载二进制文件,这是最新版,往往比 `homebrew` 提供的更新,适用于修复 Bug、添加新功能后及时使用

```bash
# arm64/aarch64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-aarch64-macos -o chsrc; chmod +x ./chsrc

# x64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x64-macos -o chsrc; chmod +x ./chsrc
```

</details>



<details>
<summary>BSD</summary>

如果已安装好了编译 `chsrc` 所需要的依赖,可直接运行:

```bash
git clone https://gitee.com/RubyMetric/chsrc.git; cd chsrc
clang -Iinclude -Ilib src/chsrc-main.c -o chsrc
```

**如果还不存在这些依赖,你将会被死锁住: 我还没有换源,我该如何安装这些依赖呢?**

这就是 [chsrc-bootstrap] 起作用的时刻,你可使用BSD系统的原生脚本语言编写 `bootstrapper`,[并向我们提交](https://github.com/RubyMetric/chsrc/issues/230)

注: `chsrc` 实现的 `FreeBSD recipe` 长期存在问题,因此一个新的 `bootstrapper` 是相当必要的,请帮助你自己和大家!

</details>



<details>
<summary>Android/Termux</summary>

Termux 中默认无 `Wget`,我们都用 `cURL` 来下载安装

```bash
# arm64/aarch64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-arm64-android -o chsrc; chmod +x ./chsrc
```

如果你所在的处理器架构没有预编译版本,可以使用 [chsrc-bootstrap]:

```bash
curl -L https://gitee.com/RubyMetric/chsrc/raw/main/bootstrap/Termux.bash | bash
```

</details>



<details>
<summary>其他平台</summary>

若你所在的平台不存在预编译好的 `chsrc`,你需要手动编译。如果已安装好了编译 `chsrc` 所需要的依赖,可直接运行:

```bash
git clone https://gitee.com/RubyMetric/chsrc.git; cd chsrc; make
```

**如果还不存在这些依赖,你将会被死锁住: 我还没有换源,我该如何安装这些依赖呢?**

这就是 [chsrc-bootstrap] 起作用的时刻,你可使用该平台原生脚本语言编写 `bootstrapper`,[并向我们提交](https://github.com/RubyMetric/chsrc/issues/230)

</details>

<br>

## 💡 使用

```bash
名称:
   chsrc - Change Source - (GPLv3+)

使用:
   chsrc <command> [options] [target] [mirror]

命令:
   help,  h                   打印此帮助,或 -h, --help
   issue, i                   查看相关issue

   list, ls, l                列出可用镜像站和可换源目标
   list  mirror|target        列出支持的: 镜像站/换源目标
   list  os|lang|ware         列出支持的: 操作系统/编程语言/软件
   list   <target>            查看该目标可用源与支持功能

   measure, m, cesu <target>  对该目标所有源测速

   get, g <target>            查看该目标当前源的使用情况

   set, s <target>            换源,自动测速后挑选最快源
   set    <target>  first     换源,使用维护团队测速第一的源
   set    <target> <mirror>   换源,指定使用某镜像站 (通过list <target>查看)
   set    <target>  <URL>     换源,用户自定义源URL
   reset  <target>            重置,使用上游默认使用的源

选项:
   -dry                       Dry Run,模拟换源过程,命令仅打印并不运行
   -scope=project|user|system 仅对本项目换源 / 用户级换源 / 系统级换源 (通过ls <target>查看)
   -ipv6                      使用IPv6测速
   -en(glish)                 使用英文输出
   -no-color                  无颜色输出
```

<br>

```bash
自动测速,寻找最快者,换源

    $ chsrc set ruby

不想自动测速的时候,可使用维护团队测试的最快镜像站

    $ chsrc set ruby first

先列出可用的镜像站,然后选择其一,如使用 RubyChina 作为镜像站

    $ chsrc ls  ruby
    $ chsrc set ruby rubychina

若有自己的镜像,可以使用自定义URL

    $ chsrc set ruby https://gems.ruby-china.com/

对支持 *项目级* 换源的目标,可以避免全局(*系统级* 或 *用户级*)换源

    $ chsrc set -scope=project bundler
    $ chsrc set -scope project pdm
```

<br>

## 编程语言开发

```bash
chsrc set ruby|rb|gem|bundler|rubygems

chsrc set python | py | pypi # 同时换 pip, poetry, pdm, uv 这4个包管理器,也可以4个独立换源
  chsrc set pip
  chsrc set poetry
  chsrc set pdm
  chsrc set uv

chsrc set rye

chsrc set node | nodejs # 同时换 npm, yarn 和 pnpm 这3个包管理器,也可以3个独立换源
  chsrc set npm
  chsrc set yarn
  chsrc set pnpm

chsrc set nvm
chsrc set bun

chsrc set perl | cpan
chsrc set php  | composer
chsrc set lua  | luarocks

chsrc set rust | cargo | crate
chsrc set rustup

chsrc set go
chsrc set java    | maven | mvn | maven-daemon | mvnd | gradle
chsrc set clojure | clojars
chsrc set dart    | pub
chsrc set flutter
chsrc set haskell | hackage | cabal | stack
chsrc set ocaml   | opam

# 同时会为 bioconductor 换源
chsrc set r | cran
chsrc set julia
```

<br>

## 操作系统

```bash
sudo chsrc set ubuntu
sudo chsrc set zorinos
sudo chsrc set linuxmint
sudo chsrc set debian
sudo chsrc set fedora
# 同时支持 Leap 和 Tumbleweed
sudo chsrc set opensuse
sudo chsrc set kali
sudo chsrc set arch
sudo chsrc set archlinuxcn
sudo chsrc set manjaro
sudo chsrc set gentoo
sudo chsrc set rocky | rockylinux
sudo chsrc set alma  | almalinux
sudo chsrc set alpine
sudo chsrc set voidlinux
sudo chsrc set solus
sudo chsrc set ros   | ros2
sudo chsrc set trisquel
sudo chsrc set linuxlite
sudo chsrc set raspi | raspberrypi
sudo chsrc set armbian
sudo chsrc set openwrt

sudo chsrc set openeuler
sudo chsrc set openanolis | anolis
sudo chsrc set openkylin
sudo chsrc set deepin

chsrc set msys2 | msys

# Android
chsrc set termux

# BSD
sudo chsrc set freebsd
sudo chsrc set openbsd
sudo chsrc set netbsd
```

<br>

## 软件

```bash
chsrc set winget
chsrc set brew      | homebrew
chsrc set cocoapods | cocoa | pod
chsrc set dockerhub | docker
chsrc set flathub   | flatpak
chsrc set nix
chsrc set guix
chsrc set emacs  | elpa
chsrc set tex    | ctan | latex | texlive | miktex
chsrc set conda  | anaconda
```

<br>

## 📝 许可证

- `chsrc` 主程序采用 `GPL-3.0-or-later` 许可证,保证该软件的永久自由
- `xy.h` 使用 `MIT` 许可证,保证该库可以在尽可能多的情况下复用

<br>

## ❤️ 致谢

感谢各个镜像站提供的优质免费镜像服务

1. [mirror.c](./src/framework/mirror.c) 包含了通用的镜像站信息
2. 各个recipe内部定义的专用镜像站

另外特别感谢以下组织或项目:

1. [校园网联合镜像站(MirrorZ)](https://help.mirrors.cernet.edu.cn/)
2. [清华大学 Tuna](https://mirrors.tuna.tsinghua.edu.cn/)
3. [上海交通大学软件源镜像服务](https://mirrors.sjtug.sjtu.edu.cn/)
4. [中国科学技术大学 Linux 用户协会](https://github.com/ustclug)
5. [Thanks Mirror 项目](https://github.com/eryajf/Thanks-Mirror) by [@eryajf](https://github.com/eryajf)

<br>

## 🚀 赞赏支持

你是否因为 `chsrc` 而受到启发、节省了时间精力 or whatever?

爱发电主页: <https://afdian.com/a/ccmywish>

<img src="https://raw.githubusercontent.com/ccmywish/support-my-oss-work/main/wechat-reward.png" alt="wechat-reward" style="width:300px;"/>

<br>

[rawstr4c]:        https://github.com/RubyMetric/rawstr4c
[chsrc-bootstrap]: ./bootstrap/

[@Aaron-212]:      https://github.com/Aaron-212
[@chenrui333]:     https://github.com/chenrui333
[@niheaven]:       https://github.com/niheaven
[@Gn3po4g]:        https://github.com/Gn3po4g
[@Jerry-Terrasse]: https://github.com/Jerry-Terrasse
[@Efterklang]:     https://github.com/Efterklang
[@wickdynex]:      https://github.com/wickdynex
[@YU-7]:           https://github.com/YU-7
[@sanchuanhehe]:   https://github.com/sanchuanhehe


================================================
FILE: bootstrap/README.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : (chsrc-bootstrap Introduction.md)
 ! Doc Authors   : 曾奥然 <ccmywish@qq.com>
 ! Contributors  : Nul None <nul@none.org>
 !               |
 ! Created On    : <2025-07-12>
 ! Last Modified : <2025-07-22>
 ! ---------------------------------------------------------- -->

# Bootstrap

```ruby
begin
  download_prebuilt_chsrc_binary_for_my_platform
rescue NoReadyMadeBinary => e
  bootstrap! e.my_platform
end
```

<br>



## 预编译产生的死锁问题

我们支持预编译的操作系统目前只有 `Windows`, `Linux`, `macOS`,支持的架构请参考[项目 README](../README.md)

某些操作系统如 BSD 家族,甚至是更小众的操作系统, 或者上述操作系统的某些架构,无法享受直接下载二进制立即使用的便利性,这导致用户需要自己编译 `chsrc`.

然而用户自己编译则面临着一个问题: **需要提前安装项目依赖**

1. 把代码 `git clone` 下来 或 下载 `zip` 包进行解压缩
2. C语言编译器
3. `GNU make` 或 `just` (这二者非强制,但是有了更好)

可是如果用户还没有换源,他/她又如何获得上述这些程序呢?**这是一把死锁,导致用户最终回到手动换源的原始农耕时代。**

<br>



## `chsrc-bootstrap` to the Rescue

`chsrc-bootstrap` 是一组使用原生脚本语言的脚本,每个脚本称为 `bootstrapper`,用来完成两件事情:

1. 帮助用户进行最基本的换源,让用户能够立即开始使用该系统安装其他软件

2. 用户自行决定是否需要安装 `chsrc`

    - 若不需要: 流程直接结束,用户已可以完成基本日常工作

    - 若需要: 帮助用户安装好所需的最少依赖,并编译安装 `chsrc`

注意,最基本的换源,即不测速,由维护者暂时决定先切换到某一个具体的源,先让系统跑起来。

### 支持的语言

上述提到的原生脚本语言只能是这些:

1. Windows: `PowerShell`, `CMD`

2. Linux: `Bash`, `sh`

    备选: `Perl`

3. macOS: `Zsh`, `Bash`, `sh`

    备选: `Ruby`, `Perl`

4. BSD: `sh`

    备选: 待议

5. 其他平台: 一切该平台支持的脚本语言,无需额外安装

<br>



## `chsrc` 与 `chsrc-bootstrap`

`chsrc` 需要实现 `chsrc-bootstrap` 中支持的平台。这是因为,`chsrc-bootstrap` 只换到了某一个具体的源,只是临时性的,后续用户可能还想要换到其他源,此时 `chsrc` 就可以接管。

而事实上,`chsrc-bootstrap` 可以完成一些操作,使得系统已经满足一些前置条件,这样的话 `chsrc` 可以在这些前置条件存在时接着换源,从而大幅减轻 `recipe` 的实现难度。

<br>



## 帮助

1. [FreeBSD 的换源](https://github.com/RubyMetric/chsrc/issues/11) 从项目一开始就是我们的目标之一,然而由于其:

    - 换源所需的步骤太多
    - 面临着特有的鸡蛋困境
    - BSD 工具和 GNU 工具总是有不兼容之处
    - 在C语言中实现困难重重

    因此我们一直没有很好的办法去实现

2. 任何你所在的平台,都可以添加到此


================================================
FILE: bootstrap/Termux.bash
================================================
#!/usr/bin/env bash
# ---------------------------------------------------------------
# SPDX-License-Identifier: GPL-3.0-or-later
# ---------------------------------------------------------------
# File Name     : Termux.bash
# File Authors  : Aoran Zeng <ccmywish@qq.com>
# Contributors  : Nul None <nul@none.org>
# Created On    : <2025-07-12>
# Last Modified : <2026-01-21>
#
# Termux:
#
#   Bootstrap Termux: https://github.com/RubyMetric/chsrc/issues/173
#
#   @consult https://help.mirrors.cernet.edu.cn/termux/
#
#   我们默认采用校园网联合镜像站提供的源
# ---------------------------------------------------------------

bs_echo() {
  echo "[chsrc-bootstrap] $*"
}

if command -v termux-change-repo &>/dev/null; then
  termux-change-repo
else

  # $PREFIX 的值为:  /data/data/com.termux/files/usr
  # 用户主目录 ~ 为: /data/data/com.termux/files/home

  # 必要的
  sed -i 's@^\(deb.*stable main\)$@#\1\ndeb https://mirrors.cernet.edu.cn/termux/apt/termux-main stable main@' $PREFIX/etc/apt/sources.list
  apt-get update

  # x11-repo
  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

  # root-repo
  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
fi

# 立即更新测试换源状态
apt-get update && apt-get upgrade

bs_echo "基础换源已完成"

read -p "是否需要安装 chsrc ? (y/n): " need_install_chsrc

if [[ $need_install_chsrc == "y" || $need_install_chsrc == "Y" ]]; then
  bs_echo "正在安装依赖项..."
  apt-get install -y gcc make git
  git clone https://gitee.com/RubyMetric/chsrc.git --depth 1
  bs_echo "依赖安装完成!"

  bs_echo "正在开始编译和安装"
  cd chsrc
  make build-in-release-mode
  make install
  bs_echo "chsrc 安装完成!"
fi


================================================
FILE: doc/01-开发与构建.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : 01-开发与构建.md
 ! Doc Authors   : 曾奥然       <ccmywish@qq.com>
 ! Contributors  : Mikachu2333  <mikachu.23333@zohomail.com>
 !               |
 ! Created On    : <2024-12-27>
 ! Last Modified : <2025-10-11>
 ! ---------------------------------------------------------- -->

# 开发 chsrc

## 依赖与开发环境

请安装好:

  1. `GCC` 或 `Clang`
  2. [just] 或 `make`
  3. `curl`
  4. [rawstr4c] (可选)

**我推荐你使用 VS Code 开发,你可以在一分钟内成功编译、运行和 Debug `chsrc`**

  1. `Ctrl-Shift-B` 直接构建
  2. `F5` 直接开始 Debug

<br>



## 获取代码

**请务必使用 dev 分支开发**

```bash
git clone https://gitee.com/RubyMetric/chsrc.git -b dev
```

关于分支的说明,可参考 [./03-CONTRIBUTING.md](./03-CONTRIBUTING.md)

<br>



## 编译运行

共有四种构建模式:

1. **`DEV mode`**
2. **`DEBUG mode`**
3. **`RELEASE mode`**
4. **`CI-RELEASE mode`**

开发时只需要前两种模式;第四种模式只在 GitHub Actions 使用。

**如果你使用 `just`,可以在 VS Code 中获得更好的体验,按 `Ctrl-Shift-B` 直接使用 DEV mode 构建**

```bash
just (b)      # 在Windows上默认使用 gcc 编译,在macOS上默认使用 clang 编译,在其他系统上默认使用 cc 编译
just CC=clang # 使用 clang 编译
just CC=gcc   # 使用 gcc   编译

# 编译出 debug 版本: chsrc-debug
just bd
# 编译出 release 版本: chsrc-release
just br
```

<br>

`make` 用户:

```bash
make (b)      # 在Windows上默认使用 cc 编译,在macOS上默认使用 clang 编译,在其他系统上默认使用 cc 编译
make CC=clang # 使用 clang 编译
make CC=gcc   # 使用 gcc   编译

# 编译出 debug 版本: chsrc-debug
make bd
# 编译出 release 版本: chsrc-release
make br
```

<br>



## Debug

**如果你使用 `just`,可以在 VS Code 中获得更好的体验,按 F5 即可立即开始 Debug**

```bash
# 重新编译出 ./chsrc-debug,并启动 GDB 调试 (在macOS上启动 LLDB 调试)
$ just debug

# 重新编译出 ./chsrc-debug,并启动 LLDB 调试
$ just DEBUGGER=lldb debug
```

<br>

`make` 用户:

```bash
# 重新编译出 ./chsrc-debug,并启动 GDB 调试 (在macOS上启动 LLDB 调试)
$ make debug

# 重新编译出 ./chsrc-debug,并启动 LLDB 调试
$ make debug DEBUGGER=lldb
```

<br>



## 测试

`just` 用户只需要替换下述 `make` 为 `just`

```bash
make test-xy  # 测试 xy.h
make test-fw  # 测试 framework
make test     # 测试上述两个
make test-cli # 测试命令
make clean
```

<br>



## 提交 PR

关于分支的说明以及如何提交代码,请参考 [./03-CONTRIBUTING.md](./03-CONTRIBUTING.md)

<br>



[rawstr4c]: https://github.com/RubyMetric/rawstr4c
[just]: https://github.com/casey/just


================================================
FILE: doc/02-提交与贡献.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : 02-提交与贡献.md
 ! Doc Authors   : 曾奥然 <ccmywish@qq.com>
 ! Contributors  : Nul None <nul@none.org>
 !               |
 ! Created On    : <2024-12-13>
 ! Last Modified : <2025-08-22>
 ! ---------------------------------------------------------- -->

# 贡献说明

## 分支

- `gh-build`:仅仅在发布版本时由 `@ccmywish` 推送,触发编译到 GitHub Releases 中
- `main`: stable,代码一定是可以编译运行的,我们假设 end users 在其他条件都得不到二进制时,会自己编译这个分支来运行 `chsrc`
- `dev`:开发分支,工作分支,在此分支上解决冲突

<br>

## 提交与审阅

当你提交 PR 的时候,一定要将 PR 指定 chsrc 原仓库的 dev 分支。

### 一个简单的 Bug

一个简单的 Bug fix,有写权限的维护者可以直接推送到主仓库的 `dev` 分支

<br>

### 不太容易修复的 Bug 以及新功能

这里要分两种情况考虑。(1)recipe 相关的 (2)framework 相关的

(1)

**如果你是 recipe Chef,则你完全负责这个 recipe,如果你拥有写权限,你可以直接推送代码到 `dev` 分支**

---

(2)

1. 需要先搜索你修改的部分涉及到的 recipe,然后提 issue @ 所有相关的 recipe Chef 来 review
2. 如果涉及了所有 recipe,则 @ framework Chef,而无需把所有 recipe 的 Chef 都喊过来,但是如果觉得有必要,可以 @ 任意你觉得有能力 review 和能给出建议的人来 review

<br>

### 最好总是 issue 或 PR

对于有写权限的维护者来说,即使是能够直接推代码,最好也都先提 issue 或 PR,因为这样能够让大家知道代码发生了哪些变动。

如果你觉得要和大家讨论,则 issue;如果你觉得没有讨论的必要了,则直接 PR 后自己立即合并即可。之所以多此一举,是因为这能够显式地记录代码的加入过程,其相当于一份文档方便未来的自己和他人查阅


================================================
FILE: doc/03-为什么拒绝使用代码格式化工具.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : 03-为什么拒绝使用代码格式化工具.md
 ! Doc Authors   :  曾奥然  <ccmywish@qq.com>
 ! Contributors  : Nul None <nul@none.org>
 ! Created On    : <2025-08-10>
 ! Last Modified : <2025-08-20>
 ! ---------------------------------------------------------- -->

# chsrc 代码风格

Ruby 的语法优美性在编程行业中具有标杆地位。Matz(松本行弘)提出的 **代码应该为人类而写,偶尔为机器执行** 这一理念,已经成为现代编程语言设计的重要指导原则。`chsrc` 项目的第一作者深受 **Ruby** 语言哲学的影响。

本项目起源于 AI 编程尚未流行的时代,所有代码全部依赖人类的耐心来维护。现在,我们的代码以及这篇文章不仅会由人类阅读,也会由 AI 阅读。我们始终坚持:**代码的可读性和维护性是项目长期发展的根本保障**。

<br>



## 为什么我们坚持不使用代码格式化工具

代码格式化工具(code formatter)在多人协作的代码仓库中确实有其价值,**参与的人越多,统一格式的需求越迫切**。然而,`chsrc` 项目经过深思熟虑后,拒绝使用代码格式化工具。让我来说明这一决定背后的深层原因。

### 被强迫使用

像 `Prettier` 这样的工具表面上带来了统一性,但其代价是什么?**它是极度专制的(opiniated)**,我们必须**完全交出代码审美的自主权**。今天我们大部分人使用 `Prettier`,**并非出于真心的认同,而是因为整个前端生态圈的集体胁迫——不用就意味着被边缘化**。

这种现象的本质令人深思:**少数 `Prettier` 维护者的个人偏好,竟然决定了全球数百万开发者的代码美学标准。这显然是一种技术独裁,坚决拒绝向格式化工具的霸权低头**。

<br>

### 一致性 ≠ 美观 ≠ 可读

格式化工具只保证了表面的一致性,就像一些校服,一致不一定代表美。同样,一致不一定代表代码就是最易读易懂的。

每一个有追求的程序员都应该保留**对代码美学的最后决定权,格式化工具的便利性不应该以牺牲美观性和可维护性为代价**。

<br>

### 满足不了我们的需求

C语言的格式化工具通常选择 `clang-format`,它的配置选项十分丰富,比 `Prettier` 要理性得多。然而,即便如此,**其配置的复杂性和局限性仍然无法满足 chsrc 对代码格式的严苛要求**。如果你是一位 `clang-format` 的配置专家,我们诚挚邀请您告诉我们如何优雅地处理以下代码场景,**也许这能改变我的立场**。

<br>



### 挑战案例

以下是我认为自动格式化工具很难完美处理的代码场景:

`=` 对齐:

```c
char *name  = va_arg (args, char*);
char *email = va_arg (args, char*);
```

复杂逻辑的 `=` 对齐:

```c
         bool matched = iterate_menu (chsrc_pl_menu, input, &target_tmp);
if (!matched) matched = iterate_menu (chsrc_os_menu, input, &target_tmp);
if (!matched) matched = iterate_menu (chsrc_wr_menu, input, &target_tmp);
```

预处理指令的层次缩进:

```c
#ifdef _WIN32
  #define XY_Build_On_Windows 1
  #define xy_on_windows true
  #ifdef XY_DEBUG
    #define xy_debug_mode 1
  #endif
#endif
```

...... 等等

<br>



## C语言代码风格

- 整体上基于 `GNU style`,但我们坚持自己的美学原则,在细节上有所改进

- 类型名: `PascalCase_t`,即 `UpperCamelCase_t`

- 函数定义和调用时,**函数名和`()`之间始终保持一个空格**,如果是在宏中,可紧凑一些,无硬性规定

- 函数和函数定义之间**一般保持2个空行**

    - 若函数之间有高度关联性,**可用1个空行**
    - 若一系列函数和一系列函数存在主题性区别,**可用3个空行**

<br>



## Markdown 写作风格

维护者很多时候不是从渲染好的界面来看 Markdown 文件的,而是阅读 Markdown 源文件,所以 Markdown 在源文件层面也要易读。

我们保持每个主题之间 **1个`<br>` + 3个空行** 的简单风格。

拒绝使用 VS Code 的 `markdownlint` 插件,**因为它总是用它狭隘的标准给我们增加了巨多的黄色下划线**。

<br>



## 其他语言代码风格

我们秉承 **入乡随俗、尊重传统** 的原则,尊重每种语言社区的既定传统。比如,`YAML` 使用2个空格,`JSON`使用4个空格,`Perl` 使用 Larry Wall 钟爱的4个空格。

我们使用 `.editorconfig` 来确保这些格式的应用。

<br>


================================================
FILE: doc/10-如何编写recipe.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : 10-如何编写recipe.md
 ! Doc Authors   : 曾奥然 <ccmywish@qq.com>
 ! Contributors  : Nul None <nul@none.org>
 !               |
 ! Created On    : <2024-08-19>
 ! Last Modified : <2026-01-21>
 ! ---------------------------------------------------------- -->

# Write A Recipe Even If You Don't Know C

## 介绍

**`chsrc` 不仅是一个命令行工具,同时也是一个体现了 Ruby on Rails 思想的 MVC 换源框架,它甚至使你能够在不了解C语言的情况下编写出新的换源方法(recipe)。**

<br>

我鼓励你为新的软件添加换源支持,因为通过 `chsrc` 框架,这将比写 shell 脚本更加轻松,你的贡献也将非常有价值。理论上每一个 `recipe` 都需要有专人长时间维护 ([招募](https://github.com/RubyMetric/chsrc/issues/275))。

- 本项目采用 `GPLv3+` 协议,是真正的**自由软件**,而非仅仅是开源软件
- 代码规范灵活遵循 `GNU` 标准(若标准干扰了可维护性,则并不采纳)
- 高度模块化,目录结构清晰易懂
- 极小依赖,极易构建,只需要 `GCC` 或 `Clang` 即可编译 (`make` 和 `just`可简化编译,但不是必需的)
- 易于将 `shell` 脚本转换为等价的 `recipe`
- 已有大量 `recipe` 可提供参考,并提供了 [recipe template] 供直接使用
- 本仓库外的子项目 [rawstr4c] 帮助你在C语言中维护复杂的字符串
- [chsrc-bootstrap] 帮助你在没有预编译 `chsrc` 的平台上 bootstrap 自己

<br>

成功案例:

- [Armbian](../src/recipe/os/APT/Armbian.c)
- [uv](../src/recipe/lang/Python/uv.c)

<br>

## 基本概念

- `target`: 所要换源的目标
- `target group`: 一个 `target` 包含了多个子 `target`,比如 `Python group` 包含了该语言的多个包管理器

- `category`: 是 `target category` 的简写,即 `target` 所属的类别,可以是 **编程语言**,**操作系统**,**软件** 三类之一

    1. 在目录中,三者分别为 `lang`, `os`, `ware`
    2. 在代码中,三者前缀分别为 `pl`, `os`, `wr`

- `mirror`: 是 `mirror site` 的简写,指镜像站,如清华大学开源软件镜像站
- `source`: 该 `target` 所能换的具体的源,由 `mirror` 提供服务,往往一个 `mirror` 会提供许多 `source`
- `recipe`: 是为一个 `target` 定义的具体换源方法,请参考 `src` 目录中的 `recipe` 目录

- `chef DSL`:是 `chef Domain Specific Language` 的简写,这是一组以 `chef_` 开头的函数,用来定义维护者信息、可用源等元信息

- **换源链接**: 指镜像站所提供的某一个具体的换源使用的URL
- **测速链接**: 用来测速的URL,与 "换源链接" 不同,可分为 **精准测速** 和 **模糊测速**

    1. 在代码中,测速链接一般使用 `smURL` (即 `speed measure URL`) 或 `speed_measure_url` 来指代
    2. 在代码中,换源链接一般使用 `repoURL` (即 `repository URL`) 或直接用 `url` 来指代

        - 为什么不用 `regurl`,因为使用术语 `repository` 的 target 远多于使用术语 `registry` 的。
        - 为什么莫名其妙使用了大小写混合的API? 因为 `smurl` 和 `repourl` 的可读性太差

- **镜像源**: 为了方便,**偶尔**我们将直接称`mirror`和/或`source`为**镜像源**,这只是一种方便性的称呼,可以统称二者,也可以根据上下文指代二者之一

<br>

## 编写 `recipe` 步骤

1. 确定你要编写的 `target` 的标准名称,创建 `Target-Name.c` 文件

    大小写需严格按官方,若名称包含空格,需使用 `-` 代替空格

2. 根据类别将上述文件放在 `recipe/` 目录的某个子目录中

3. 复制 [recipe template] 的内容到上述文件中,并替换 `<...>` 占位符

4. 参考现有 `recipe` 的写法

    1. 看一眼就能上手的参照物是 [PHP recipe](../src/recipe/lang/PHP.c)
    2. 最好的参照物是 [Ruby recipe](../src/recipe/lang/Ruby/Ruby.c)
    3. 组换源参照物是 [Python group recipe](../src/recipe/lang/Python/Python.c)

5. 在 [Wiki] 中记录的镜像站中寻找可用源;可以额外补充镜像站

6. 使用 chef DSL 定义 `_prelude()` 函数

    该函数将填充 target 所有的必要信息,包括维护信息、换源信息

7. [设置/修改 "换源链接" 和 "测速链接" (how?)](./11-如何设置换源链接与测速链接.md)

8. 按需实现 `_setsrc()` `_getsrc()` `_resetsrc()`, 可以使用这些函数:

    1. `framework/core.c` 中以 `chsrc_` 开头的所有函数或宏
    2. `xy.h` 中以 `xy_` 开头的所有函数或宏
    3. `chec.c` 中以 `chef_` 开头的所有函数或宏
    4. `helper.c` 中以 `hp_` 开头的所有函数或宏

    一个简单的方法是,在 VS Code 中按快捷键 `Ctrl-T` 搜索上述三种前缀

9. 在 `recipe/menu.c` 中登记此 target

10. [编译、运行、测试 (how?)](./01-开发与构建.md),若无问题可提交 Pull Request

<br>

## 开发准则

1. 代码高度可移植

2. Convention over Configuration

3. [NO UFO 原则: 不要乱丢文件到$HOME等目录,尤其是使用各种隐晦的文件名](https://www.yuque.com/ccmywish/blog/no-ufo)

    `chsrc` 主程序不提供配置文件,不提供数据文件,干净无污染。那么在实现 `recipe` 的时候,除了备份文件外,也不要污染用户环境。

<br>

[rawstr4c]: https://github.com/RubyMetric/rawstr4c
[chsrc-bootstrap]: ../bootstrap/
[recipe template]: ../src/recipe/recipe-template.c
[Wiki]: https://github.com/RubyMetric/chsrc/wiki


================================================
FILE: doc/11-如何设置换源链接与测速链接.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : 11-如何设置换源链接与测速链接.md
 ! Doc Authors   : 曾奥然 <ccmywish@qq.com>
 ! Contributors  : Nul None <nul@none.org>
 !               |
 ! Created On    : <2025-08-11>
 ! Last Modified : <2026-01-21>
 ! ---------------------------------------------------------- -->

# 新增/修改 "换源链接"

在 `_prelude()` 函数中,在 `def_sources_begin()` 的位置的**第二列**,新增/修改你想要替换的链接。

**注: 以下代码仅起解释作用,JavaScript换源的真正实现可能不同**

```c
def_sources_begin()
{&UpstreamProvider, "https://registry.npmjs.org/",                     FeedByPrelude},
{&NpmMirror,        "https://registry.npmmirror.com",                  FeedByPrelude},
{&Huawei,           "https://mirrors.huaweicloud.com/repository/npm/", FeedByPrelude},
{&Tencent,          "https://mirrors.cloud.tencent.com/npm/",          FeedByPrelude},
{&某新镜像站,       "某镜像站提供的换源链接",                         FeedByPrelude}
def_sources_end()

//

// 调整上述某一个镜像站的所提供源的 "换源链接"
chef_set_repoURL (this, &UpstreamProvider, "新的换源链接");
```

<br>


# 设置/修改 "测速链接"

在 `_prelude()` 函数中,在 `def_sources_begin()` 的位置的**第三列**,设置/修改你想要替换的链接。

1. 在下面代码的第一行中,我们直接给了一个链接,**这就是精准测速链接**
2. 在下面代码的第二行和第三行中,我们都设置了一个宏 `DelegateToMirror`,这意味着我们没有直接提供精准测速链接,而是让 `chsrc` 去测试其对应镜像站定义的测速链接

    - `NpmMirror` 是专用镜像站,所以其测速链接被设置为了 `ACCURATE`,即精准测速
    - `Huawei` 是通用镜像站,所以其测速链接被设置为了 `ROUGH `,即模糊测速

3. 在下面代码的第四行中,我们设置了一个宏 `FeedByPrelude`,这意味着我们将在 `_prelude()` 函数的后续动态计算 URL

**注: 以下代码仅起解释作用,JavaScript换源的真正实现可能不同**

```c
def_sources_begin()
{&UpstreamProvider, "https://registry.npmjs.org/",                     "https://registry.npmjs.org/BigFile.tar.gz"},
{&NpmMirror,        "https://registry.npmmirror.com",                  DelegateToMirror},
{&Huawei,           "https://mirrors.huaweicloud.com/repository/npm/", DelegateToMirror},
{&Tencent,          "https://mirrors.cloud.tencent.com/npm/",          FeedByPrelude},
def_sources_end()

//

// 调整/设置上述某一个镜像站的所提供源的 "精准测速链接"
chef_set_smURL (this, &UpstreamProvider, "新的测速链接");
// 设置上述某一个镜像站的所提供源的 "精准测速链接" 设置为 "换源链接" + postfix
chef_set_smURL_with_postfix (this, &UpstreamProvider, "/dir/BigFile.tar.gz");
// 基于 "换源链接" 做更自定义的操作
chef_set_smURL_with_func (this, &UpstreamProvider, func, data);

// 把所有上述源中还未设置 "精准测速链接" 的源进行设置
chef_set_rest_smURL_with_postfix (this, "/dir/BigFile.tar.gz");
chef_set_rest_smURL_with_func (this, func, data);

// 调整某一个镜像站(Provider)的 "测速链接"
chef_set_provider_smURL (&Tencent, "https://mirrors.cloud.tencent.com/npm/BigFile.tar.gz");
// 调整某一个镜像站(Provider)的 "测速精度"
chef_set_provider_sm_accuracy (&UpstreamProvider, ROUGH);
```


================================================
FILE: doc/50-协作者与维护者.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : 50-协作者与维护者.md
 ! Doc Authors   : 曾奥然 <ccmywish@qq.com>
 ! Contributors  : Nul None <nul@none.org>
 !               |
 ! Created On    : <2024-12-06>
 ! Last Modified : <2025-08-22>
 ! ---------------------------------------------------------- -->

# 协作者与维护者

想要达到最理想的维护状态,每一个 recipe 都需要有专人长时间维护。**我们的代码里使用了 recipe (某个菜的烹饪方法) 这个词,因而整个项目便和 "饮食" 有关,比如 `menu`: 汇集了所有的 target 的菜单。因此,我们的维护者和贡献者身份依然使用了这个惯例:**

1. **Chef**

    品控 (主厨): 对一个 recipe 完全负责,有写权限时可以直接推代码

    **目前项目的发展阶段还处于 *外行实现内行* 的情况,比如 Homebrew recipe,实现者根本不是 Homebrew 的真实用户,只是根据各种文档来实现,然后等待用户反馈。所以这里当前的实现者最多只能是 Cook,无法承担 Chef 的责任**

2. **Cook**

    掌勺:一个 recipe 的主要作者

3. **Saucier**

    调味:一个 recipe 的次要贡献者 (除主要作者外的其他人)

<br>

**Chef 采用申请制,每个 recipe 仅有1人,请提交 PULL REQUEST 在对应的 recipe 文件中添加自己,并在 [issue #275
](https://github.com/RubyMetric/chsrc/issues/275) 留言。**


================================================
FILE: doc/README.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : (Document Introduction.md)
 ! Doc Authors   : 曾奥然 <ccmywish@qq.com>
 ! Contributors  : Nul None <nul@none.org>
 !               |
 ! Created On    : <2024-12-27>
 ! Last Modified : <2025-08-22>
 ! ---------------------------------------------------------- -->

# 文档说明

E2E (End-to-End) 开发文档:

- 开发环境准备,如何编译和测试,请参考 [01-开发与构建.md](./01-开发与构建.md)
- 直接推送还是提交 PR,请参考 [02-提交与贡献.md](./02-提交与贡献.md)
- 代码风格,请参考 [03-为什么拒绝使用代码格式化工具.md](./03-为什么拒绝使用代码格式化工具.md)

<br>

具体 recipe 相关:

- 如何编写一个具体的 recipe,请参考 [10-如何编写recipe.md](./10-如何编写recipe.md)
- 如何修改换源链接、模糊/精准测速链接,请参考 [11-如何设置换源链接与测速链接.md](./11-如何设置换源链接与测速链接.md)

<br>

- 关于维护者身份的说明,请参考 [50-协作者与维护者.md](./50-协作者与维护者.md)

<br>

用户手册:

1. [chsrc.1](./chsrc.1)
2. [chsrc.texi](./chsrc.texi)

<br>

## 贡献指导

若有任何问题,可在 [GitHub discussions](https://github.com/RubyMetric/chsrc/discussions) 中询问和讨论

<br>


================================================
FILE: doc/chsrc.1
================================================
.\" --------------------------------------------------------------
.\" SPDX-License-Identifier: GFDL-1.3-or-later
.\" --------------------------------------------------------------
.\" Doc Type      : Man Page
.\" Doc Authors   : 曾奥然 <ccmywish@qq.com>
.\" Contributors  : Nul None <nul@none.org>
.\"               |
.\" Created On    : <2024-08-21>
.\" Last Modified : <2026-02-24>
.\" ----------------------------------------------------------------

.TH  chsrc  1  "2026-02-24"  "v0.2.5"  "RubyMetric chsrc"

.SH NAME
chsrc - Change Source for every software on every platform from the command line

.SH SYNOPSIS
.SY chsrc
<command> [options] [target] [mirror]
.YS


.SH DESCRIPTION
.SS 基本命令
.TP
.B help
打印此帮助,或 h, -h, --help
.TP
.B issue
查看相关issue

.TP
\fBlist\fR (或 \fBls\fR, 或 \fBl\fR)
列出可用镜像源,和可换源目标
.TP
.B list mirror/target
列出可用镜像源,或可换源目标
.B list os/lang/ware
列出可换源的操作系统/编程语言/软件

.SS 测速命令
.TP
.B measure/cesu \fI<target>\fI
对该目标所有源测速

.SS 查看配置命令
.TP
.B list \fI<target>\fR
查看该目标可用源与支持功能
.TP
.B get \fI<target>\fR
查看该目标当前源的使用情况

.SS 换源命令
.TP
.B set \fI<target>\fR
换源,自动测速后挑选最快源
.TP
.B set \fI<target>\fR first
换源,使用维护团队测速第一的源
.TP
.B set \fI<target>\fR \fI<mirror>\fR
换源,指定使用某镜像站 (通过list <target>查看)
.TP
.B set \fI<target>\fR \fI<https://url>\fR
换源,用户自定义源URL
.TP
.B reset \fI<target>\fR
重置,使用上游默认使用的源



.SH OPTIONS
.TP
\fB-dry\fR
Dry Run,模拟换源过程,命令仅打印并不运行
.TP
\fB-scope\fR
设置换源的作用域,可选值有:project|user|system|default (通过ls \fI<target>\fR查看支持情况)
.TP
\fB-ipv6\fR
使用IPv6测速
.TP
\fB-en(glish)\fR
使用英文输出
.TP
\fB-no-color\fR
无颜色输出


.SH "EXIT STATUS"
.br
.TP
0
正常执行,一般表示换源成功
.TP
1
用户环境导致的错误,如命令缺失
.TP
2
chsrc 暂未实现支持
.TP
3
维护者导致的镜像站、源信息相关错误
.TP
4
致命错误,由内部Bug导致
.TP
5
致命未知错误,往往代表内部未知Bug



.SH EXAMPLES
.EX
# 测速,寻找最快者,换源
$ chsrc set ruby

# 列出可用的镜像站
# 使用 RubyChina 作为镜像站
$ chsrc ls  ruby
$ chsrc set ruby rubychina

# 可以使用自定义URL
$ chsrc set ruby https://gems.ruby-china.com/

# 使用维护团队测试的最快镜像站
$ chsrc set ruby first
.EE


.SH FILES
.B
遵循 No UFO(Unidentified File Objects)原则:https://www.yuque.com/ccmywish/blog/no-ufo
.PP
因此不会有任何文件存放在你的计算机中!



.\" .SH SEE ALSO

.SH AUTHOR
Written by Aoran Zeng, Heng Guo and contributors. (See chsrc.c)

.SH "REPORTING BUGS"
On Gitee:  https://gitee.com/RubyMetric/chsrc/issues
.br
On GitHub: https://github.com/RubyMetric/chsrc/issues

.SH COPYRIGHT
Copyright (C) 2026 Aoran Zeng, Heng Guo.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
.br
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


================================================
FILE: doc/chsrc.texi
================================================
@c --------------------------------------------------------------
@c SPDX-License-Identifier: GFDL-1.3-or-later
@c --------------------------------------------------------------
@c Doc Type      : Texinfo
@c Doc Authors   : 曾奥然 <ccmywish@qq.com>
@c Contributors  : Nul None <nul@none.org>
@c               |
@c Created On    : <2024-08-22>
@c Last Modified : <2026-02-24>
@c --------------------------------------------------------------

\input texinfo
@setfilename chsrc.info
@settitle chsrc

@set Chsrc_Version v0.2.5
@set Doc_Publish_Date 2026-02-24

@copying
@comment 这是软件copyright,不是文档copyright,因此不放在titlepage
Copyright @copyright{} 2023-2026 曾奥然, 郭恒
@end copying

@titlepage
@title chsrc printed manual
@subtitle Change Source everywhere for every software!
@author 曾奥然
@c @insertcopying
For chsrc @value{Chsrc_Version}
@page
@end titlepage


@contents

@node Top
@top chsrc on-terminal manual

The 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}}

@exdent 使用: chsrc <command> [options] [target] [mirror]

Exit status:

@display
0 正常执行,一般表示换源成功
1 用户环境导致的错误,如命令缺失
2 chsrc 暂未实现支持
3 维护者导致的镜像站、源信息相关错误
4 致命错误,由内部Bug导致
5 致命未知错误,往往代表内部未知Bug
@end display

@noindent
维护:
@itemize
@item On Gitee:  https://gitee.com/RubyMetric/chsrc/issues
@item On GitHub: https://github.com/RubyMetric/chsrc/issues
@end itemize


@menu
* commands:: 命令
* options:: 选项
* examples:: 例子
@end menu

@insertcopying



@node commands
@chapter 命令

@section 基本命令
@table @samp
@item help
打印此帮助,或 h, -h, --help
@item issue
查看相关issue

@item list (或 ls, 或 l)
列出可用镜像源,和可换源目标

@item list mirror/target
列出可用镜像源,或可换源目标

@item list os/lang/ware
列出可换源的操作系统/编程语言/软件
@end table


@section 测速命令
@table @samp
@item measure <target>
@itemx cesu   <target>
对该目标所有源测速
@end table

@page
@section 查看配置命令
@table @samp
@item list <target>
查看该目标可用源与支持功能

@item get <target>
查看该目标当前源的使用情况
@end table


@section 换源命令
@table @samp
@item set <target>
换源,自动测速后挑选最快源

@item set <target> first
换源,使用维护团队测速第一的源

@item set <target> <mirror>
换源,指定使用某镜像站 (通过list <target>查看)

@item set <target> https://url
换源,用户自定义源URL

@item reset <target>
重置,使用上游默认使用的源
@end table



@node options
@chapter 选项
@table @samp
@item -dry
Dry Run,模拟换源过程,命令仅打印并不运行

@item -ipv6
使用IPv6测速

@item -scope
设置换源的作用域,可选值有:project|user|system|default (通过ls <target>查看支持情况)

@item -en(glish)
使用英文输出

@item -no-color
无颜色输出
@end table



@node examples
@chapter 例子
@example
# 测速,寻找最快者,换源
$ chsrc set ruby

# 列出可用的镜像站
# 使用 RubyChina 作为镜像站
$ chsrc ls  ruby
$ chsrc set ruby rubychina

# 可以使用自定义URL
$ chsrc set ruby https://gems.ruby-china.com/

# 使用维护团队测试的最快镜像站
$ chsrc set ruby first
@end example

@bye


================================================
FILE: include/.keep
================================================


================================================
FILE: justfile
================================================
#!/usr/bin/env just --justfile
# --------------------------------------------------------------
# SPDX-License-Identifier: GPL-3.0-or-later
# --------------------------------------------------------------
# Build File    : justfile
# File Authors  : 曾奥然      <ccmywish@qq.com>
# Contributors  : Mikachu2333 <mikachu.23333@zohomail.com>
#               |
# Created On    : <2025-06-18>
# Last Modified : <2025-10-15>
#
# 该文件主要用于在原生Windows上执行项目的基本任务,而不借助于
# GNU make 以及相应的 MSYS2、Cygwin 环境
# --------------------------------------------------------------
# just (build)											-> chsrc.exe
# just bd (build-in-debug-mode)			-> chsrc-debug.exe
# just br (build-in-release-mode)		-> chsrc-release.exe
# just debug
# just test
# just clean
#
# just STATIC=1 br  	静态链接 (注意只能在 br 任务中使用)
#
# 不支持 just DEBUG=1,请直接使用 just bd (等价于 just build-in-debug-mode)
#
# --------------------------------------------------------------
# 注意,由于我们要在 GitHub Actions 上编译 x32 版的 chsrc,所以需要使用 make,
# 而不清楚 just 在 MINGW32 中的情况,所以我们在此 justfile 中并不实现关于 CI 的功能
# --------------------------------------------------------------

set windows-shell := ['cmd', '/c']

CC := if os() == 'windows' {
	"gcc"
} else if os() == 'macos' {
	"clang"
} else {
	"cc"
}

DEBUGGER := if os() == 'windows' {
	"gdb"
} else if os() == 'macos' {
	"lldb"
} else {
	"gdb"
}

CFLAGS_chk_Clang := if os() == 'windows' {
  if CC == 'clang' {
    '-target x86_64-pc-windows-gnu'
  } else {''}
} else {''}


CFLAGS_base := '-Iinclude -Ilib ' + CFLAGS_chk_Clang

WARN := '-Wall -Wextra -Wno-unused-variable -Wno-unused-function -Wno-missing-braces -Wno-misleading-indentation' + ' ' + \
	'-Wno-missing-field-initializers -Wno-unused-parameter -Wno-sign-compare'
CFLAGS_warn := WARN


CFLAGS_debug := '-g -DXY_DEBUG'

DevMode-Target-Name     := 'chsrc'
DebugMode-Target-Name   := 'chsrc-debug'
ReleaseMode-Target-Name := 'chsrc-release'

STATIC := '0'

CFLAGS_static := "-static"

CFLAGS_chk_static := if STATIC == '1' {
	CFLAGS_static
} else { "" }


CFLAGS_optimization := "-O2"


CFLAGS_dev_mode_prompt 	   := CFLAGS_base
CFLAGS_debug_mode_prompt 	 := CFLAGS_base + ' ' + CFLAGS_debug
CFLAGS_release_mode_prompt := CFLAGS_base + ' ' + CFLAGS_optimization + ' ' + CFLAGS_chk_static

CFLAGS_dev_mode     := CFLAGS_dev_mode_prompt     + ' ' + CFLAGS_warn
CFLAGS_debug_mode   := CFLAGS_debug_mode_prompt   + ' ' + CFLAGS_warn
CFLAGS_release_mode := CFLAGS_release_mode_prompt + ' ' + CFLAGS_warn

#=======================

BIN_xy := if os() == 'windows' {'xy.exe'} else {'./xy'}
BIN_fw := if os() == 'windows' {'fw.exe'} else {'./fw'}
BIN_rm := if os() == 'windows' {'del'}    else {'rm'}
#=======================
alias b := build-in-dev-mode
alias bd:= build-in-debug-mode
alias br:= build-in-release-mode
alias build:=build-in-dev-mode
alias d := debug
alias t := test
alias check := test
alias c := clean

default: build-in-dev-mode

build-in-dev-mode:
	@echo Starting: Build in DEV mode: '{{CC}}' {{CFLAGS_dev_mode_prompt}} -o {{DevMode-Target-Name}}
	@{{CC}} src/chsrc-main.c {{CFLAGS_dev_mode}} -o {{DevMode-Target-Name}}
	@echo Finished: Build in DEV mode

build-in-debug-mode:
	@echo Starting: Build in DEBUG mode: '{{CC}}' {{CFLAGS_debug_mode_prompt}} -o {{DebugMode-Target-Name}}
	@{{CC}} src/chsrc-main.c {{CFLAGS_debug_mode}} -o {{DebugMode-Target-Name}}
	@echo Finished: Build in DEBUG mode

build-in-release-mode:
  @echo Starting: Build in RELEASE mode: '{{CC}}' {{CFLAGS_release_mode_prompt}} -o {{ReleaseMode-Target-Name}}
  @{{ if os() == 'windows' { \
        '(if exist chsrc.res del chsrc.res)' + \
        ' & windres src/resource/chsrc.rc -O coff -o chsrc.res' \
      } else { '' } }}
  @{{ if os() == 'windows' { \
      CC + ' src/chsrc-main.c chsrc.res ' + CFLAGS_release_mode + ' -o ' + ReleaseMode-Target-Name \
    } else { \
      CC + ' src/chsrc-main.c '           + CFLAGS_release_mode + ' -o ' + ReleaseMode-Target-Name \
    } }}
  @echo Finished: Build in RELEASE mode

debug: build-in-debug-mode
  @{{DEBUGGER}} {{DebugMode-Target-Name}}

test: test-xy test-fw

# 这两个测试文件都用 DEBUG mode
test-xy:
	@{{CC}} test/xy.c {{CFLAGS_debug_mode}} -o xy
	@{{BIN_xy}}

test-fw:
	@{{CC}} test/fw.c {{CFLAGS_debug_mode}} -o fw
	@{{BIN_fw}}

fastcheck:
	@perl ./test/cli.pl fastcheck

test-cli:
	@perl ./test/cli.pl

clean:
	-@{{BIN_rm}} *.exe
	-@{{BIN_rm}} *.res
	-@{{BIN_rm}} xy
	-@{{BIN_rm}} fw
	-@{{BIN_rm}} chsrc
	-@{{BIN_rm}} chsrc-debug
	-@{{BIN_rm}} chsrc-release
	-@{{BIN_rm}} README.md.bak*

# 使用: just rawstr4c [--debug] Markdown.md
# rawstr4c *args:
#	@{{ if os() == 'windows' { 'tool\\rawstr4c\\run\\run.bat' } else { 'bash ./tool/rawstr4c/run/run.sh' } }} {{args}}


================================================
FILE: lefthook.yml
================================================
# ---------------------------------------------------------------
# Lefthook File : lefthook.yml
# File Authors  : 曾奥然 <ccmywish@qq.com>
# Contributors  : Nul None <nul@none.org>
#               |
# Created On    : <2025-10-28>
# Last Modified : <2025-10-30>
# ---------------------------------------------------------------

min_version: 2.0.1

pre-commit:
  only:
    - ref: dev
  parallel: false
  jobs:
    - name: 试运行 DEBUG mode
      # 触发所有 _prelude() 函数检查
      run: |
        just build-in-debug-mode
        ./chsrc-debug get pip
      glob: "*.{c,h}"
      exclude: test/*

    - name: 测试 xy.h
      run: just test-xy
      glob:
        - lib/xy.h
        - test/xy.c

    - name: 测试 framework
      run: just test-fw
      glob:
        - "src/framework/*.{c,h}"
        - src/chsrc-main.c
        - test/fw.c

post-merge:
  only:
    - ref: main
  jobs:
    - name: 测试编译 DEV mode
      run: just build-in-dev-mode

pre-push:
  only:
    - ref: gh-build
  jobs:
    - name: 测试编译 RELEASE mode
      run: just build-in-release-mode

    - name: 测试运行
      run: just test-cli


================================================
FILE: lib/xy.h
================================================
/** ------------------------------------------------------------
 * Copyright © 2023-2026 曾奥然, 郭恒
 * SPDX-License-Identifier: MIT
 * -------------------------------------------------------------
 * Lib Authors   :  曾奥然 <ccmywish@qq.com>
 *               |   郭恒  <2085471348@qq.com>
 * Contributors  : Mikachu2333 <mikachu.23333@zohomail.com>
 *               | juzeon <skyjuzheng@gmail.com>
 *               | BingChunMoLi <bingchunmoli@bingchunmoli.com>
 *               |
 * Created On    : <2023-08-28>
 * Last Modified : <2025-12-31>
 *
 *
 *                     xy: 襄阳、咸阳
 *
 * 为跨平台命令行应用程序准备的 C11 实用函数和宏 (utilities)
 *
 * 该库的特点是混合多种编程语言风味 (绝大多数为 Ruby),每个 API
 * 均使用 @flavor 标注其参考依据
 * ------------------------------------------------------------*/

#ifndef XY_H
#define XY_H

#define _XY_Version       "v0.2.2.0-2025/10/28"
#define _XY_Maintain_URL  "https://github.com/RubyMetric/chsrc/blob/dev/lib/xy.h"
#define _XY_Maintain_URL2 "https://gitee.com/RubyMetric/chsrc/blob/dev/lib/xy.h"

#if defined(__STDC__) && __STDC_VERSION__ < 201112L
#   error "xy.h requires C11 or later, please use a new compiler which at least supports C11"
#endif

#if defined(__STDC__) && __STDC_VERSION__ < 201710L
#   warning "xy.h recommends a C17 or later compiler"
#endif

#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h> // opendir() closedir()

#if defined(__STDC__) && __STDC_VERSION__ >= 202311
  #define XY_Deprecate_This(msg) [[deprecated(msg)]]
#elif defined(__GNUC__) || defined(__clang__)
  #define XY_Deprecate_This(msg) __attribute__((deprecated(msg)))
#elif defined(_MSC_VER)
  #define XY_Deprecate_This(msg) __declspec(deprecated(msg))
#else
  #define XY_Deprecate_This(msg)
#endif



/* 全局变量 与 全局状态 */
struct
{
  bool enable_color;

  bool inited;

  bool on_windows;
  bool on_linux;
  bool on_macos;
  bool on_bsd;
  bool on_android;

  /* @flavor 同 just 中的 os_family(),只区分 windows, unix */
  char *os_family;
  char *os_devnull;
}
xy =
{
  .enable_color = true,

  /* 由 xy_init() 赋值 */

  .inited = false,

  .on_windows = false,
  .on_linux = false,
  .on_macos = false,
  .on_bsd = false,
  .on_android = false,

  .os_family = NULL,
  .os_devnull = NULL
};



#ifdef _WIN32
  #define XY_Build_On_Windows 1

  #include <windows.h>
  #include <shlobj.h>

#elif defined(__linux__) || defined(__linux)
  #define XY_Build_On_Linux 1
  #define XY_Build_On_Unix  1

#elif defined(__APPLE__)
  #define XY_Build_On_macOS 1
  #define XY_Build_On_Unix  1

#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
  #define XY_Build_On_BSD  1
  #define XY_Build_On_Unix 1
#endif



/**
 *  assert() 会被 NDEBUG 关闭,但我们也没有必要强制开启它,还是留给用户定义
 */
// #undef NDEBUG
#define xy_noop() ((void)0)

#define assert_str(a, b) assert (xy_streql ((a), (b)))

#define xy_throw(reason) assert(!reason)

/**
 * @depreacated 避免消极用语
 *
 * @flavor Perl, PHP, Raku
 */
// #define die xy_throw

/**
 * @depreacated 避免消极用语
 */
// #define xy_panic xy_throw

#define xy_unsupported()    xy_throw("Unsuppoted")
#define xy_unimplemented()  xy_throw("Unimplemented temporarily")
#define xy_unreached()      xy_throw("This code shouldn't be reached")
#define xy_cant_be_null(p)  if(!p) xy_throw("This pointer can't be null")


static inline void
_xy_internal_warn (char *str)
{
  fprintf (stderr, "[xy.h] %s\n", str);
}

static void _xy_print_int    (int n) {printf ("%d", n);}
static void _xy_print_long   (long n) {printf ("%ld", n);}
static void _xy_print_long_long (long long n) {printf ("%lld", n);}
static void _xy_print_float  (float n) {printf ("%f", n);}
static void _xy_print_double (double n) {printf ("%f", n);}
static void _xy_print_bool   (bool b) {printf("%s", (b) ? "true" : "false");}
static void _xy_print_str    (char *str) {printf ("%s", str);}
static void _xy_print_const_str (const char *str) {printf ("%s", str);}

static void _xy_println_int    (int n) {printf ("%d\n", n);}
static void _xy_println_long   (long n) {printf ("%ld\n", n);}
static void _xy_println_long_long (long long n) {printf ("%lld\n", n);}
static void _xy_println_float  (float n) {printf ("%f\n", n);}
static void _xy_println_double (double n) {printf ("%f\n", n);}
static void _xy_println_bool   (bool b) {printf("%s\n", (b) ? "true" : "false");}
static void _xy_println_str    (char *str) {printf ("%s\n", str);}
static void _xy_println_const_str (const char *str) {printf ("%s\n", str);}

/**
 * @flavor Ruby, Python
 */
#define print(x) _Generic((x), \
  int:       _xy_print_int,  \
  long:      _xy_print_long, \
  long long: _xy_print_long_long, \
  float:     _xy_print_float,  \
  double:    _xy_print_double, \
  bool:      _xy_print_bool, \
  char *:    _xy_print_str,  \
  const char *:   _xy_print_const_str, \
  default:   xy_throw("Unsupported type for print()!") \
)(x)

/**
 * @flavor JVM family, Rust
 */
#define println(x) _Generic((x), \
  int:       _xy_println_int,  \
  long:      _xy_println_long, \
  long long: _xy_println_long_long, \
  float:     _xy_println_float,  \
  double:    _xy_println_double, \
  bool:      _xy_println_bool, \
  char *:    _xy_println_str,  \
  const char *:   _xy_println_const_str, \
  default:   xy_throw("Unsupported type for println()/say()!") \
)(x)
/* @flavor Raku, Perl */
#define say println
/* @flavor PHP */
#define echo println
/**
 * @flavor HTML
 */
void br ()                   { puts (""); }
void p (const char *s)       { printf ("%s\n", s); }


#define xy_c_array_len(arr) (sizeof (arr) / sizeof (arr[0]))


static inline void *
xy_malloc0 (size_t size)
{
  void *ptr = malloc (size);
  memset (ptr, 0, size);
  return ptr;
}


/**
 * @brief 替换指针内容并自动释放旧内存
 *
 * @param pptr    指向要被替换内存区域的指针的指针
 *                *pptr 可为 NULL
 * @param new_mem 新的内存区域
 */
static inline void
xy_ptr_replace (char **pptr, char *new_mem)
{
  xy_cant_be_null (pptr);

  if (*pptr)
    free (*pptr);

  *pptr = new_mem;
}


/******************************************************
 *                      String
 ******************************************************/

/**
 * @brief 将 str 中所有的 pat 字符串替换成 replace,返回一个全新的字符串
 *
 * @flavor Ruby: String#gsub
 *
 * @param str     原字符串
 * @param pat     要替换的字符串
 * @param replace 替换成的字符串
 *
 * @return 替换后的新字符串
 */
static char *
xy_str_gsub (const char *str, const char *pat, const char *replace)
{
  size_t replace_len = strlen (replace);
  size_t pat_len = strlen (pat);

  int unit = replace_len - pat_len;
  if (unit <= 0)
    unit = 0;

  size_t len = strlen (str);

  const char *cur = str;
  int count = 0;

  while (cur < str + len)
    {
      char *fnd = strstr (cur, pat);
      if (fnd)
        {
          count++;
          cur = fnd + pat_len;
        }
      else
        break;
    }
  // puti(count); DEBUG 匹配次数

  char *ret = malloc (unit * count + len + 1);
  char *retcur = ret;

  cur = str;
  while (cur < str + len)
    {
      char *fnd = strstr (cur, pat);
      if (fnd)
        {
          ptrdiff_t diff = fnd - cur;
          strncpy (retcur, cur, diff);
          cur = fnd + pat_len;

          retcur += diff;
          strcpy (retcur, replace);
          retcur += replace_len;
        }
      else
        break;
    }
  strcpy (retcur, cur);

  return ret;
}


/**
 * @flavor 见 xy_strcat()
 */
static char *
xy_2strcat (const char *str1, const char *str2)
{
  size_t len = strlen (str1);
  size_t size = len + strlen (str2) + 1;
  char *ret = malloc (size);
  strcpy (ret, str1);
  strcpy (ret + len, str2);
  return ret;
}


/**
 * @brief 将多个字符串连接成一个字符串
 *
 * @flavor C语言存在 strcat(),然而限制比较大,我们重新实现

 *   'concat' 这个API广泛应用于包括 Ruby、JavaScript、JVM family、C#
 *
 *   但由于 xy_str_concat() 显著长于 xy_strcat(),而这个 API 在 chsrc 中
 *   又大量使用,所以我们选择后者这个更简短的形式
 *
 * @param count 连接的字符串数量
 * @param ...   连接的字符串
 *
 * @return 拼接的新字符串
 */
static char *
xy_strcat (unsigned int count, ...)
{
  size_t al_fixed = 256;
  char *ret = calloc (1, al_fixed);
  // 已分配次数
  int al_times = 1;
  // 当前已分配量
  size_t al_cur = al_fixed;

  const char *str = NULL;
  // 需要分配的量
  size_t al_need = 0;
  // 用于 strcpy() 到 ret 的哪个位置
  char *cur = ret + 0;

  va_list args;
  va_start (args, count);

  for (int i = 0; i < count; i++)
    {
      bool need_realloc = false;

      str = va_arg (args, const char *);
      al_need += strlen (str) + 1;
      while (al_need > al_cur)
        {
          al_times += 1;
          al_cur = al_times * al_fixed;
          need_realloc = true;
        }
      // printf("al_times %d, al_need %zd, al_cur %zd\n", al_times, al_need,
      // al_cur);
      if (need_realloc)
        {
          ptrdiff_t diff = cur - ret;
          ret = realloc (ret, al_cur);
          cur = ret + diff;
        }
      if (NULL == ret)
        {
          _xy_internal_warn ("xy_strcat(): No availble memory to allocate!");
          return NULL;
        }
      strcpy (cur, str);
      // puts(ret);
      cur += strlen (str);
    }
  va_end (args);

  *cur = '\0';
  return ret;
}


/**
 * @brief 复制一个字符串,返回复制的新字符串
 *
 * @param str 要复制的字符串
 *
 * @return 复制的新字符串
 */
static char *
xy_strdup (const char *str)
{
  if (!str)
    {
      _xy_internal_warn ("xy_strdup(): called with NULL!");
      return NULL;
    }

  size_t len = strlen (str);
  char *new = xy_malloc0 (len + 1);
  strcpy (new, str);
  return new;
}

#define _XY_Str_Bold      1
#define _XY_Str_Faint     2
#define _XY_Str_Italic    3
#define _XY_Str_Underline 4
#define _XY_Str_Blink     5
#define _XY_Str_Cross     9

#define xy_str_to_bold(str)      _xy_str_to_terminal_style (_XY_Str_Bold, str)
#define xy_str_to_faint(str)     _xy_str_to_terminal_style (_XY_Str_Faint, str)
#define xy_str_to_italic(str)    _xy_str_to_terminal_style (_XY_Str_Italic, str)
#define xy_str_to_underline(str) _xy_str_to_terminal_style (_XY_Str_Underline, str)
#define xy_str_to_blink(str)     _xy_str_to_terminal_style (_XY_Str_Blink, str)
#define xy_str_to_cross(str)     _xy_str_to_terminal_style (_XY_Str_Cross, str)

#define _XY_Str_Red     31
#define _XY_Str_Green   32
#define _XY_Str_Yellow  33
#define _XY_Str_Blue    34
#define _XY_Str_Magenta 35
#define _XY_Str_Cyan    36

#define xy_str_to_red(str)     _xy_str_to_terminal_style (_XY_Str_Red, str)
#define xy_str_to_green(str)   _xy_str_to_terminal_style (_XY_Str_Green, str)
#define xy_str_to_yellow(str)  _xy_str_to_terminal_style (_XY_Str_Yellow, str)
#define xy_str_to_blue(str)    _xy_str_to_terminal_style (_XY_Str_Blue, str)
#define xy_str_to_magenta(str) _xy_str_to_terminal_style (_XY_Str_Magenta, str)
#define xy_str_to_purple        xy_str_to_magenta
#define xy_str_to_cyan(str)    _xy_str_to_terminal_style (_XY_Str_Cyan, str)

static char *
_xy_str_to_terminal_style (int style, const char *str)
{
  char *color_fmt_str = NULL;

  if (!xy.enable_color)
    {
      color_fmt_str = "%s";
      goto new_str;
    }

  switch (style)
    {
    case _XY_Str_Red:
      color_fmt_str = "\e[31m%s\e[0m"; break;
    case _XY_Str_Green:
      color_fmt_str = "\e[32m%s\e[0m"; break;
    case _XY_Str_Yellow:
      color_fmt_str = "\e[33m%s\e[0m"; break;
    case _XY_Str_Blue:
      color_fmt_str = "\e[34m%s\e[0m"; break;
    case _XY_Str_Magenta:
      color_fmt_str = "\e[35m%s\e[0m"; break;
    case _XY_Str_Cyan:
      color_fmt_str = "\e[36m%s\e[0m"; break;
    case _XY_Str_Bold:
      color_fmt_str = "\e[1m%s\e[0m"; break;
    case _XY_Str_Faint:
      color_fmt_str = "\e[2m%s\e[0m"; break;
    case _XY_Str_Italic:
      color_fmt_str = "\e[3m%s\e[0m"; break;
    case _XY_Str_Underline:
      color_fmt_str = "\e[4m%s\e[0m"; break;
    case _XY_Str_Blink:
      color_fmt_str = "\e[5m%s\e[0m"; break;
    case _XY_Str_Cross:
      color_fmt_str = "\e[9m%s\e[0m"; break;
    }


  size_t len = 0;
new_str:
  // -2 把中间%s减掉
  len = strlen (color_fmt_str) - 2;
  char *buf = malloc (strlen (str) + len + 1);
  sprintf (buf, color_fmt_str, str);
  return buf;
}


static bool
xy_streql (const char *str1, const char *str2)
{
  if (NULL==str1 || NULL==str2)
    {
      return false;
    }
  return strcmp (str1, str2) == 0 ? true : false;
}

static bool
xy_streql_ic (const char *str1, const char *str2)
{
  if (NULL == str1 || NULL == str2)
    {
      return false;
    }

  size_t len1 = strlen (str1);
  size_t len2 = strlen (str2);
  if (len1 != len2)
    {
      return false;
    }

  for (size_t i = 0; i < len1; i++)
    {
      if (tolower (str1[i]) != tolower (str2[i]))
        {
          return false;
        }
    }
  return true;
}


/**
 * @flavor Ruby: String#end_with?
 */
static bool
xy_str_end_with (const char *str, const char *suffix)
{
  size_t len1 = strlen (str);
  size_t len2 = strlen (suffix);

  if (0 == len2)
    return true; // 空字符串直接返回
  if (len1 < len2)
    return false;

  const char *cur1 = str + len1 - 1;
  const char *cur2 = suffix + len2 - 1;

  for (int i = 0; i < len2; i++)
    {
      if (*cur1 != *cur2)
        return false;
      cur1--;
      cur2--;
    }
  return true;
}

/**
 * @flavor Ruby: String#start_with?
 */
static bool
xy_str_start_with (const char *str, const char *prefix)
{
  if (NULL==str || NULL==prefix)
    {
      return false;
    }

  size_t len1 = strlen (str);
  size_t len2 = strlen (prefix);

  if (0 == len2)
    return true; // 空字符串直接返回
  if (len1 < len2)
    return false;

  const char *cur1 = str;
  const char *cur2 = prefix;

  for (int i = 0; i < len2; i++)
    {
      if (*cur1 != *cur2)
        return false;
      cur1++;
      cur2++;
    }
  return true;
}

/**
 * @flavor Ruby: String#delete_prefix
 */
static char *
xy_str_delete_prefix (const char *str, const char *prefix)
{
  bool yes = xy_str_start_with (str, prefix);
  if (!yes)
    {
      return xy_strdup (str);
    }
  else
    {
      size_t len = strlen (prefix);
      return xy_strdup (str + len);
    }
}

/**
 * @flavor Ruby: String#delete_suffix
 */
static char *
xy_str_delete_suffix (const char *str, const char *suffix)
{
  char *new = xy_strdup (str);
  bool yes = xy_str_end_with (str, suffix);
  if (!yes)
    return new;

  size_t len1 = strlen (str);
  size_t len2 = strlen (suffix);
  char *cur = new + len1 - len2;
  *cur = '\0';
  return new;
}

/**
 * @flavor Ruby: String#strip
 */
static char *
xy_str_strip (const char *str)
{
  xy_cant_be_null (str);

  const char *start = str;
  while (*start && strchr ("\n\r\v\t\f ", *start))
    start++;

  if ('\0' == *start)
    return xy_strdup ("");

  const char *end = start + strlen (start) - 1;
  while (end >= start && strchr ("\n\r\v\t\f ", *end))
    end--;

  size_t len = (size_t) (end - start + 1);
  char *ret = xy_malloc0 (len + 1);
  memcpy (ret, start, len);
  ret[len] = '\0';
  return ret;
}

typedef struct
{
  bool   found;
  size_t begin;
  size_t end;
}
XyStrFindResult_t;

/**
 * @brief 查找子串,返回是否命中以及子串在原串中的起止位置(0 基,end 为闭区间)
 */
static XyStrFindResult_t
xy_str_find (const char *str, const char *substr)
{
  XyStrFindResult_t result = { .found = false, .begin = 0, .end = 0 };

  if (!str || !substr)
    return result;

  if ('\0' == substr[0])
    {
      result.found = true;
      return result;
    }

  const char *pos = strstr (str, substr);
  if (!pos)
    return result;

  result.found = true;
  result.begin = (size_t) (pos - str);
  result.end = result.begin + strlen (substr) - 1;
  return result;
}

/**
 * @brief 获取字符串下一行的内容
 *
 * @note 将忽略开头的换行,截取至下一个换行前(不含换行符)
 */
static char *
xy_str_next_nonempty_line (const char *str)
{
  if (!str)
    return xy_strdup ("");

  const char *cur = str;
  while (*cur == '\n')
    cur++;

  if ('\0' == *cur)
    return xy_strdup ("");

  const char *newline = strchr (cur, '\n');
  size_t len = newline ? (size_t) (newline - cur) : strlen (cur);

  char *ret = xy_malloc0 (len + 1);
  strncpy (ret, cur, len);
  ret[len] = '\0';
  return ret;
}



/**
 * @brief 读取文件内容并返回字符串,失败时返回空字符串
 *
 * @note 已处理 \r\n 和 \r,返回的字符串均为 \n 换行
 *
 * @flavor Ruby: IO::read
 */
static char *
xy_file_read (const char *path)
{
  FILE *fp = fopen (path, "rb");
  if (!fp)
    return xy_strdup ("");

  if (fseek (fp, 0, SEEK_END) != 0)
    {
      fclose (fp);
      return xy_strdup ("");
    }

  long size = ftell (fp);
  if (size < 0)
    {
      fclose (fp);
      return xy_strdup ("");
    }
  rewind (fp);

  char *buf = xy_malloc0 ((size_t) size + 1);
  if (!buf)
    {
      fclose (fp);
      return xy_strdup ("");
    }

  size_t read_bytes = fread (buf, 1, (size_t) size, fp);
  if (read_bytes < (size_t) size && ferror (fp))
    {
      fclose (fp);
      free (buf);
      return xy_strdup ("");
    }

  fclose (fp);
  buf[read_bytes] = '\0';

  char *formatted_str = xy_str_gsub (buf, "\r\n", "\n");
  xy_ptr_replace (&formatted_str, xy_str_gsub (formatted_str, "\r", "\n"));

  free (buf);

  return formatted_str;
}



/******************************************************
 *                      Logging
 ******************************************************/

#define _XY_Log_Plain   000000001
#define _XY_Log_Success 000000001 << 1
#define _XY_Log_Info    000000001 << 2
#define _XY_Log_Warn    000000001 << 3
#define _XY_Log_Error   000000001 << 4

#define xy_log(prompt, str)  _xy_log (_XY_Log_Plain,   prompt, str)
#define xy_succ(prompt,str)  _xy_log (_XY_Log_Success, prompt, str)
#define xy_info(prompt,str)  _xy_log (_XY_Log_Info,    prompt, str)
#define xy_warn(prompt,str)  _xy_log (_XY_Log_Warn,    prompt, str)
#define xy_error(prompt,str) _xy_log (_XY_Log_Error,   prompt, str)

static void
_xy_log (int level, const char *prompt, const char *content)
{
  char *str = NULL;

  bool to_stderr = false;

  /**
   * 'app: content'
   */
  if (level & _XY_Log_Plain)
    {
      str = xy_strcat (3, prompt,  ": ", content);
    }
  else if (level & _XY_Log_Success)
    {
      str = xy_strcat (3, prompt,  ": ", xy_str_to_green (content));
    }
  else if (level & _XY_Log_Info)
    {
      str = xy_strcat (3, prompt,  ": ", xy_str_to_blue (content));
    }
  else if (level & _XY_Log_Warn)
    {
      str = xy_strcat (3, prompt,  ": ", xy_str_to_yellow (content));
      to_stderr = true;
    }
  else if (level & _XY_Log_Error)
    {
      str = xy_strcat (3, prompt,  ": ", xy_str_to_red (content));
      to_stderr = true;
    }
  else
    {
      xy_unreached();
    }

  if (to_stderr)
    {
      fprintf (stderr, "%s\n", str);
    }
  else
    {
      puts (str);
    }
  free (str);
}


/**
 * @flavor brkt 系列输出受 Python 的 pip 启发,为了输出方便,使用 xy.h 的程序应该
 *
 *  1.若想完全自定义颜色和输出位置:
 *
 *    应基于下述 xy_log_brkt_to 定义自己的输出函数
 *
 *  2.若想自定义颜色,而保持输出到stdout:
 *
 *    应基于下述 xy_log_brkt 定义
 *
 *  3.若对log无细致要求,想要快速使用log功能:
 *
 *    应基于下述 xy_<level>_brkt 定义自己的 app_<level>_brkt(),或直接使用 xy_<level>_brkt
 */

static void
xy_log_brkt_to (const char *prompt, const char *content, FILE *stream)
{
  char *str = xy_strcat (4, "[", prompt, "] ", content);
  fprintf (stream, "%s\n", str);
  free (str);
}

#define xy_log_brkt(prompt1,prompt2,content)   _xy_log_brkt(_XY_Log_Plain,  prompt1,prompt2,content)
#define xy_succ_brkt(prompt1,prompt2,content)  _xy_log_brkt(_XY_Log_Success,prompt1,prompt2,content)
#define xy_info_brkt(prompt1,prompt2,content)  _xy_log_brkt(_XY_Log_Info,   prompt1,prompt2,content)
#define xy_warn_brkt(prompt1,prompt2,content)  _xy_log_brkt(_XY_Log_Warn,   prompt1,prompt2,content)
#define xy_error_brkt(prompt1,prompt2,content) _xy_log_brkt(_XY_Log_Error,  prompt1,prompt2,content)

static void
_xy_log_brkt (int level, const char *prompt1, const char *prompt2, const char *content)
{
  char *str = NULL;

  bool to_stderr = false;

  if (level & _XY_Log_Plain)
    {
      str = xy_strcat (6, "[", prompt1, " ", prompt2, "] ", content);
    }
  else if (level & _XY_Log_Success)
    {
      /* [app 成功]  [app success] */
      str = xy_strcat (6,
        "[", xy_str_to_green (prompt1), " ", xy_str_to_bold (xy_str_to_green (prompt2)), "] ", xy_str_to_green (content));
    }
  else if (level & _XY_Log_Info)
    {
      /* [app 信息]  [app info]
         [app 提示]  [app notice]
      */
      str = xy_strcat (6,
        "[", xy_str_to_blue (prompt1), " ", xy_str_to_bold (xy_str_to_blue (prompt2)), "] ", xy_str_to_blue (content));
    }
  else if (level & _XY_Log_Warn)
    {
      /* [app 警告]  [app warn] */
      str = xy_strcat (6,
        "[", xy_str_to_yellow (prompt1), " ", xy_str_to_bold (xy_str_to_yellow (prompt2)), "] ", xy_str_to_yellow (content));
      to_stderr = true;
    }
  else if (level & _XY_Log_Error)
    {
      /* [app 错误]  [app error] */
      str = xy_strcat (6,
        "[", xy_str_to_red (prompt1), " ", xy_str_to_bold (xy_str_to_red (prompt2)), "] ", xy_str_to_red (content));
      to_stderr = true;
    }
  else
    {
      xy_unreached();
    }

  if (to_stderr)
    {
      fprintf (stderr, "%s\n", str);
    }
  else
    {
      puts (str);
    }
  free (str);
}



/******************************************************
 *                      cross OS
 ******************************************************/

static char *
xy_quiet_cmd (const char *cmd)
{
  char *ret = NULL;

  if (xy.on_windows)
    ret = xy_2strcat (cmd, " >nul 2>nul ");
  else
    ret = xy_2strcat (cmd, " 1>/dev/null 2>&1 ");

  return ret;
}


/**
 * @brief 执行 `cmd`,返回其输出到 stdout 的内容中的第 `n` 行,并对已经遍历过的行执行 `func`
 *
 * @param  cmd   要执行的命令
 * @param   n    指定命令执行输出到 stdout 内容中的某一行,0 表示最后一行,n (n>0) 表示第n行
 * @param  func  对遍历时经过的行的内容,进行函数调用,如果返回 true,则提前停止遍历
 *
 * @return
 *   1. 第 `n` 行的内容
 *   或
 *   2. `func` 调用后返回为 true 的行
 *
 * @note
 *   1. 由于目标行第 `n` 行会被返回出来,所以 `func` 并不执行目标行,只会执行遍历过的行
 *   或
 *   2. 由于 `func` 调用后返回为 true 的行会被返回出来,所以该返回出的行也被 `func` 执行过了
 */
static char *
xy_run_iter_lines (const char *cmd,  unsigned long n,  bool (*func) (const char *))
{
  const int size = 512;
  char *buf = (char *) malloc (size);

  FILE *stream = popen (cmd, "r");
  if (stream == NULL)
    {
      _xy_internal_warn ("xy_run_iter_lines(): popen() failed");
      return NULL;
    }

  char *ret = NULL;
  unsigned long count = 0;

  while (true)
    {
      if (NULL == fgets (buf, size, stream))
        break;
      /* 存在换行的总是会把换行符读出来,删掉 */
      ret = xy_str_delete_suffix (buf, "\n");
      count += 1;
      if (n == count)
        break;
      if (func)
        {
           if (func (ret))
            break;
        }
    }

  pclose (stream);
  return ret;
}

/**
 * @brief 执行命令 `cmd`,返回第 `n` 行输出到 stdout 的内容
 *
 * @return 返回第 `n` 行输出到 stdout 的内容
 */
static char *
xy_run (const char *cmd, unsigned long n)
{
  return xy_run_iter_lines (cmd, n, NULL);
}


/**
 * @brief 执行命令 `cmd`,仅返回其 Exit Code,stdout 与 stderr 均不输出到终端
 *
 * @return 返回 `cmd` 的 Exit Code
 */
int
xy_run_get_status (char *cmd)
{
  char * command = xy_quiet_cmd (cmd);

  int status = system (command);
  return status;
}


/**
 * @brief 获得执行命令 `cmd` 输出到 stdout 的内容,而 stderr 依然输出到终端
 *
 * @param[in]  cmd    要执行的命令
 * @param[out] output 捕获的标准输出,
 *                    为NULL时表示不关心stdout输出,但依然允许stderr输出
 *
 * @return 返回命令的执行状态
 */
static int
xy_run_get_stdout (const char *cmd, char **output)
{
  int cap  = 8192; /* 假如1行100个字符,大约支持80行输出 */
  char *buf = (char *) xy_malloc0 (cap);

  FILE *stream = popen (cmd, "r");
  if (stream == NULL)
    {
      _xy_internal_warn ("xy_run_get_stdout(): popen() failed");
      return -1;
    }

  int size = 0;
  size_t n;
  while ((n = fread (buf + size, 1, cap - size, stream)) > 0) {
    size += n;
    if (size == cap)
      {
        cap *= 2;
        char *new_buf = realloc (buf, cap);
        buf = new_buf;
      }
    }
  buf[size] = '\0';

  int status = pclose (stream);

  if (output)
    *output = buf;

    return status;
}



/**
 * @brief 该函数返回所在 os family 的对应字符串
 */
static const char *
xy_os_depend_str (const char *str_for_win, const char *str_for_unix)
{
  if (xy.on_windows)
    return str_for_win;
  else
    return str_for_unix;
}


/**
 * @brief 返回当前操作系统的 HOME 目录
 *
 * @note  Windows 上返回 %USERPROFILE%,Linux 等返回 $HOME
 * @warning Windows 上要警惕 Documents 等目录被移动位置的情况,避免使用本函数的 HOME 路径直接拼接 Documents,应参考 _xy_win_documents() 的实现
 */
#define xy_os_home _xy_os_home ()
static char *
_xy_os_home ()
{
  char *home = NULL;
  if (xy.on_windows)
    home = getenv ("USERPROFILE");
  else
    home = getenv ("HOME");
  return home;
}


/**
 * @brief 返回 Windows 上的 Documents 目录
 *
 * @note 警告,不可使用 HOME 目录直接拼接,若用户移动了 Documents,将导致错误
 * @warning 非 Windows 返回 NULL
 */
static char *
_xy_win_documents ()
{
#ifdef XY_Build_On_Windows
  char documents_path[MAX_PATH];
  HRESULT result = SHGetFolderPathA (NULL, CSIDL_MYDOCUMENTS, NULL,
                                     SHGFP_TYPE_CURRENT, documents_path);

  if (SUCCEEDED (result))
    return xy_strdup (documents_path);

  return xy_2strcat (xy_os_home, "\\Documents");
#else
  return NULL;
#endif
}

#define xy_win_powershell_profile _xy_win_powershell_profile ()
#define xy_win_powershellv5_profile _xy_win_powershellv5_profile ()

/**
 * @brief 返回 Windows 上 pwsh (>=v5) 的配置文件路径
 *
 * @warning 非 Windows 返回 NULL
 */
static char *
_xy_win_powershell_profile ()
{
  if (xy.on_windows)
    {
      char *documents_dir = _xy_win_documents ();
      char *profile_path = xy_2strcat (documents_dir, "\\PowerShell\\Microsoft.PowerShell_profile.ps1");
      free (documents_dir);
      return profile_path;
    }
  else
    return NULL;
}


/**
 * @brief 返回 Windows 上自带的 powershell (v5) 的配置文件路径
 *
 * @warning 非 Windows 返回 NULL
 */
static char *
_xy_win_powershellv5_profile ()
{
  if (xy.on_windows)
    {
      char *documents_dir = _xy_win_documents ();
      char *profile_path = xy_2strcat (documents_dir, "\\WindowsPowerShell\\Microsoft.PowerShell_profile.ps1");
      free (documents_dir);
      return profile_path;
    }
  else
    return NULL;
}

#define xy_zshrc  "~/.zshrc"
#define xy_bashrc "~/.bashrc"
#define xy_fishrc "~/.config/fish/config.fish"

/**
 * @note Windows上,`path` 不要夹带变量名,因为最终 access() 不会帮你转换
 */
static bool
xy_file_exist (const char *path)
{
  char *expanded_path = NULL;
  const char *check_path = path;

  if (xy_str_start_with (path, "~"))
    {
      expanded_path = xy_2strcat (xy_os_home, path + 1);
      check_path = expanded_path;
    }

  // 0 即 F_OK
  bool result = (0 == access (check_path, 0)) ? true : false;
  if (expanded_path) free (expanded_path);
  return result;
}

/**
 * @note `xy_file_exist()` 和 `xy_dir_exist()` 两个函数在所有平台默认都支持使用 '~',
 *       但实现中都没有调用 `xy_normalize_path()`,以防万一,调用前可能需要用户手动调用它
 */
static bool
xy_dir_exist (const char *path)
{
  char *allocated_dir = NULL;
  const char *dir = path;
  if (xy.on_windows)
    {
      if (xy_str_start_with (path, "~"))
        {
          allocated_dir = xy_2strcat (xy_os_home, path + 1);
          dir = allocated_dir;
        }
    }

  if (xy.on_windows)
    {
#ifdef XY_Build_On_Windows
      // 也可以用 opendir() #include <dirent.h>
      DWORD attr = GetFileAttributesA (dir);

      bool result = false;
      if (attr == INVALID_FILE_ATTRIBUTES)
        {
          // Q: 我们应该报错吗?
          result = false;
        }
      else if (attr & FILE_ATTRIBUTE_DIRECTORY)
        {
          result = true;
        }
      else
        {
          result = false;
        }
      if (allocated_dir) free (allocated_dir);
      return result;
#endif
    }
  else
    {
      char *tmp_cmd = xy_2strcat ("test -d ", dir);
      int status = system (tmp_cmd);
      free (tmp_cmd);
      bool result = (0==status);
      if (allocated_dir) free (allocated_dir);
      return result;
    }

  return false;
}

/**
 * @brief 规范化路径
 *
 * @details
 *   1. 删除路径左右两边多出来的空白符
 *      - 防止通过间接方式得到的路径包含了空白字符 (如 grep 出来的结果)
 *      - 防止维护者多写了空白字符
 *   2. 将 ~ 转换为绝对路径
 *   3. 在Windows上,使用标准的 \ 作为路径分隔符
 */
static char *
xy_normalize_path (const char *path)
{
  char *new = xy_str_strip (path);

  if (xy_str_start_with (new, "~"))
    {
      char *tmp = xy_str_delete_prefix (new, "~");
      char *joined = xy_2strcat (xy_os_home, tmp);
      free (tmp);
      xy_ptr_replace (&new, joined);
    }

  if (xy.on_windows)
    {
      xy_ptr_replace (&new, xy_str_gsub (new, "/", "\\"));
    }
  return new;
}


/**
 * @brief 返回一个路径的父目录名
 *
 * @note
 *   - 返回的是真正的 "目录名" (就像文件名一样),而不是 "路径",所以一定是不含末尾斜杠的
 *   - 在Windows上,使用标准的 \ 作为路径分隔符
 */
static char *
xy_parent_dir (const char *path)
{
  char *dir = xy_normalize_path (path);

  /* 不管是否为Windows,全部统一使用 / 作为路径分隔符,方便后续处理 */
  xy_ptr_replace (&dir, xy_str_gsub (dir, "\\", "/"));

  if (xy_str_end_with (dir, "/"))
    xy_ptr_replace (&dir, xy_str_delete_suffix (dir, "/"));

  char *last = NULL;

  last = strrchr (dir, '/');
  if (!last)
    {
      /* 路径中没有一个 / 是很奇怪的,我们直接返回 . 作为当前目录 */
      return ".";
    }
  *last = '\0';

  /* Windows上重新使用 \ 作为路径分隔符 */
  if (xy.on_windows)
    {
      xy_ptr_replace (&dir, xy_str_gsub (dir, "/", "\\"));
    }
  return dir;
}


/**
 * @internal 仅由 xy_init () 调用
 */
void
_xy_detect_os ()
{
  /**
   * 首先判断是否为 Windows
   *
   * SystemDrive 为 C:
   */
  char *drive = getenv ("SystemDrive");
  if (drive)
    {
      char path[256];
      snprintf (path, sizeof (path), "%s\\Users", drive);
      DIR *d = opendir (path);
      if (d)
        {
          xy.on_windows = true;
          xy.os_family = "windows";
          closedir (d);
          return;
        }
    }

  /* 判断 Linux */
  FILE *fp = fopen ("/proc/version", "r");
  if (fp)
    {
      char buf[256] = {0};
      fread (buf, 1, sizeof (buf) - 1, fp);
      fclose (fp);
      if (strstr (buf, "Linux"))
        {
          xy.on_linux = true;
          xy.os_family = "unix";
          return;
        }
    }

  /**
   * 判断 Android
   *
   * @consult https://android.googlesource.com/platform/system/core/+/refs/heads/main/rootdir/init.environ.rc.in
   */
  char *android_env = getenv ("ANDROID_ROOT");
  if (android_env)
    {
      if (xy_str_find (android_env, "/system").found)
        {
          xy.on_android = true;
          xy.os_family = "unix";
          return;
        }
    }

  /* 判断 macOS */
  DIR *d = opendir ("/System/Applications");
  if (d)
    {
      closedir (d);
      d = opendir ("/Library/Apple");
      if (d)
        {
          xy.on_macos = true;
          xy.os_family = "unix";
          closedir (d);
          return;
        }
    }

  /* 最后判断 BSD */
  fp = popen ("uname -s", "r");
  if (fp)
    {
      char buf[256];
      fgets (buf, sizeof (buf), fp);
      pclose (fp);
      if (strstr (buf, "BSD") != NULL)
        {
          xy.on_bsd = true;
          xy.os_family = "unix";
          return;
        }
    }
  else
    {
      DIR *bsd_dir = opendir ("/etc/rc.d");
      if (bsd_dir)
        {
          closedir (bsd_dir);
          xy.on_bsd = true;
          xy.os_family = "unix";
          return;
        }
    }

  if (!(xy.on_windows || xy.on_linux || xy.on_android || xy.on_macos || xy.on_bsd))
    xy_throw ("Unknown operating system");
}


void
xy_use_utf8 ()
{
#ifdef XY_Build_On_Windows
  SetConsoleOutputCP (65001);
#endif
}


/**
 * @note 该函数必须被首先调用,方能使用各个跨操作系统的函数
 */
void
xy_init ()
{
  _xy_detect_os ();

  if (xy.on_windows)
    xy.os_devnull = "nul";
  else
    xy.os_devnull = "/dev/null";

  xy_use_utf8 ();

  xy.inited = true;
}


/******************************************************
 *                      Container
 ******************************************************/
typedef struct XySeqItem_t
{
  struct XySeqItem_t *prev;
  struct XySeqItem_t *next;

  void *data;
}
XySeqItem_t;

typedef struct XySeq_t
{
  XySeqItem_t *first_item;
  XySeqItem_t *last_item;

  uint32_t length;
}
XySeq_t;


XySeq_t*
xy_seq_new (void)
{
  XySeq_t *seq = xy_malloc0 (sizeof (XySeq_t));
  if (!seq) return NULL;

  seq->first_item = NULL;
  seq->last_item = NULL;
  seq->length = 0;

  return seq;
}

/**
 * @flavor Python: len()
 */
uint32_t
xy_seq_len (XySeq_t *seq)
{
  xy_cant_be_null (seq);
  return seq->length;
}

/**
 * @flavor Ruby: Enumerable#first
 */
void *
xy_seq_first (XySeq_t *seq)
{
  xy_cant_be_null (seq);
  return seq->first_item ? seq->first_item->data : NULL;
}

/**
 * @flavor Ruby: Enumerable#last
 */
void *
xy_seq_last (XySeq_t *seq)
{
  xy_cant_be_null (seq);
  return seq->last_item ? seq->last_item->data : NULL;
}

/**
 * @flavor Ruby: Array#at
 *
 * @note 序号从1开始
 *
 * @return 如果seq中并没有第n个数据,则返回NULL
 */
void *
xy_seq_at (XySeq_t *seq, int n)
{
  xy_cant_be_null (seq);

  if (0 == n) xy_throw ("The index must begin from 1, not 0");

  if (1 == n) return seq->first_item ? seq->first_item->data : NULL;

  XySeqItem_t *it = seq->first_item;
  for (uint32_t i = 1; i < n && it; i++)
    {
      it = it->next;
    }
  return it ? it->data : NULL;
}


/**
 * @flavor Perl: push
 */
void
xy_seq_push (XySeq_t *seq, void *data)
{
  xy_cant_be_null (seq);

  XySeqItem_t *it = xy_malloc0 (sizeof (XySeqItem_t));;

  it->data = data;
  it->prev = NULL;
  it->next = NULL;

  // 更新 item 间关系
  XySeqItem_t *l = seq->last_item;
  if (l)
    {
      it->prev = l;
      l->next = it;
    }

  // 更新 seq 信息
  seq->last_item = it;
  if (0==seq->length)
    seq->first_item = it;

  seq->length++;
}


/**
 * @flavor Perl: pop
 */
void *
xy_seq_pop (XySeq_t *seq)
{
  xy_cant_be_null (seq);

  if (0==seq->length) return NULL;

  // 更新 item 间关系
  XySeqItem_t *l = seq->last_item;
  XySeqItem_t *p = l->prev;
  // 考虑 seq 当前只有1项的情况
  if (p) p->next = NULL;
  l->prev = NULL;

  // 更新 seq 信息
  seq->last_item = p;
  // 考虑 seq 当前只有1项的情况
  if (!p) seq->first_item = NULL;
  seq->length--;

  void *data = l->data;
  free (l);
  return data;
}


/**
 * @flavor Ruby: Array#each
 */
void
xy_seq_each (XySeq_t *seq, void (*func) (void *, void *), void *user_data)
{
  xy_cant_be_null (seq);
  xy_cant_be_null (func);

  for (XySeqItem_t *it = seq->first_item; it; it = it->next)
    {
      func (it->data, user_data);
    }
}

/**
 * @flavor Ruby: Enumerable#find
 */
void *
xy_seq_find (XySeq_t *seq, bool (*func) (void *, void *), void *user_data)
{
  xy_cant_be_null (seq);
  xy_cant_be_null (func);

  for (XySeqItem_t *it = seq->first_item; it; it = it->next)
    {
      if (func (it->data, user_data))
        {
          return it->data;
        }
    }
  return NULL;
}



#define _XY_Map_Buckets_Count 97

struct _XyHashBucket_t
{
  struct _XyHashBucket_t *next;
  char *key;
  void *value;
};

typedef struct XyMap_t
{
  struct _XyHashBucket_t **buckets;

  uint32_t length;
}
XyMap_t;


XyMap_t *
xy_map_new ()
{
  XyMap_t *map = xy_malloc0 (sizeof (XyMap_t));
  map->buckets = xy_malloc0 (sizeof (struct _XyHashBucket_t *) * _XY_Map_Buckets_Count);

  map->length = 0;

  return map;
}


uint32_t
xy_map_len (XyMap_t *map)
{
  xy_cant_be_null (map);
  return map->length;
}


unsigned long
xy_hash (const char* str)
{
  unsigned long h = 5381;
  int c;
  while ((c = *str++))
    h = ((h << 5) + h) + c; /* h * 33 + c */
  return h;
}


/**
 * @flavor JavaScript: map.set
 */
void
xy_map_set (XyMap_t *map, const char *key, void *value)
{
  xy_cant_be_null (map);
  xy_cant_be_null (key);

  unsigned long hash = xy_hash (key);
  uint32_t index = hash % _XY_Map_Buckets_Count;

  // 若 key 已经存在
  struct _XyHashBucket_t *maybe = map->buckets[index];
  while (maybe)
    {
      if (xy_streql (maybe->key, key))
        {
          maybe->value = value;
          return;
        }
      maybe = maybe->next;
    }

  // 若 key 不存在
  struct _XyHashBucket_t *bucket = xy_malloc0 (sizeof (struct _XyHashBucket_t));

  bucket->key = xy_strdup (key);
  bucket->value = value;
  bucket->next = map->buckets[index];
  map->buckets[index] = bucket;

  map->length++;
}


/**
 * @flavor JavaScript: map.get
 */
void *
xy_map_get (XyMap_t *map, const char *key)
{
  xy_cant_be_null (map);
  xy_cant_be_null (key);

  unsigned long hash = xy_hash (key);
  uint32_t index = hash % _XY_Map_Buckets_Count;

  struct _XyHashBucket_t *maybe = map->buckets[index];
  while (maybe)
    {
      if (xy_streql (maybe->key, key))
        {
          return maybe->value;
        }
      maybe = maybe->next;
    }

  return NULL;
}

/**
 * @flavor Ruby: Hash#each
 */
void
xy_map_each (
  XyMap_t *map,
  void (*func) (const char *key, void *value, void *user_data),
  void *user_data)
{
  xy_cant_be_null (map);
  xy_cant_be_null (func);

  for (uint32_t i = 0; i < _XY_Map_Buckets_Count; i++)
    {
      struct _XyHashBucket_t *bucket = map->buckets[i];
      while (bucket)
        {
          func (bucket->key, bucket->value, user_data);
          bucket = bucket->next;
        }
    }
}


#endif


================================================
FILE: pkg/AUR/README.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : README.md
 ! Doc Authors   : 曾奥然 <ccmywish@qq.com>
 ! Contributors  : Nil Null <nil@null.org>
 !               |
 ! Created On    : <2025-06-15>
 ! Last Modified : <2025-06-16>
 ! ---------------------------------------------------------- -->

# AUR package

本文档说明了 `chsrc` 项目的 AUR 包的相关情况

<br>

## 相关文件

CI 维护者 [@Jerry-Terrasse](https://github.com/Jerry-Terrasse)

- [.github/workflows/pub-AUR-chsrc-git.yml](../../.github/workflows/pub-AUR-chsrc-git.yml)
- [.github/workflows/pub-AUR-chsrc-and-chsrc-bin.yml`](../../.github/workflows/pub-AUR-chsrc-git.yml)

<br>

## 分发

位于 https://aur.archlinux.org/packages

- [chsrc-bin](https://aur.archlinux.org/packages/chsrc-bin): 从 GitHub Releases 直接下载的二进制文件

- [chsrc](https://aur.archlinux.org/packages/chsrc):从 GitHub Releases 的代码构建

- [chsrc-git](https://aur.archlinux.org/packages/chsrc-git):从最新源码构建的版本,偶尔可能不稳定


================================================
FILE: pkg/README.md
================================================
# Packages

## 分发情况

- [x] `Homebrew`
- [x] `Scoop`
- [x] `WinGet`
- [x] `AUR`
- [ ] `Flatpak`
- [ ] `snap`
- [ ] ...

<br>

```bash
$ brew install chsrc

$ scoop install chsrc

$ winget install RubyMetric.chsrc

yay -S chsrc-bin # Binary from GitHub Release
yay -S chsrc     # Build  from GitHub Release
yay -S chsrc-git # Build  from the latest main branch (stable)
```

<br>

- Homebrew

  https://github.com/Homebrew/homebrew-core/blob/master/Formula/c/chsrc.rb

- Scoop

  https://github.com/ScoopInstaller/Main/blob/master/bucket/chsrc.json

- WinGet

  https://github.com/microsoft/winget-pkgs/tree/master/manifests/r/RubyMetric/chsrc

- AUR:

  - https://aur.archlinux.org/packages/chsrc-bin

  - https://aur.archlinux.org/packages/chsrc

  - https://aur.archlinux.org/packages/chsrc-git

<br>


## 打包情况

- [x] `deb`

<br>


================================================
FILE: pkg/deb/BUILD.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : BUILD.md
 ! Doc Authors   : sanchuanhehe <wyihe5520@gmail.com>
 ! Contributors  :  曾奥然 <ccmywish@qq.com>
 !               |
 ! Created On    : <2025-06-14>
 ! Last Modified : <2025-06-16>
 ! ---------------------------------------------------------- -->

# 构建 deb package

## 准备

安装构建所需的依赖:

```bash
sudo apt-get update
sudo apt-get install build-essential debhelper devscripts fakeroot
```

<br>

## 构建

```bash
git clone https://github.com/RubyMetric/chsrc.git
cd chsrc

# 进入 deb 目录
cd pkg/deb

# 执行构建命令
./Makefile deb-make
```

### 调试构建

```bash
# 启用详细输出
DEB_BUILD_OPTIONS="nocheck" debuild -us -uc -b

# 检查构建日志
less ../chsrc_*.build

# 检查包内容
dpkg --contents ../chsrc_*.deb
# 或
dpkg-deb --contents ../chsrc_*.deb
```

### 交叉编译

为不同架构进行构建:

```bash
# For ARM64
CC=aarch64-linux-gnu-gcc dpkg-buildpackage -us -uc -b -aarm64

# For ARMv7 (armhf)
CC=arm-linux-gnueabihf-gcc dpkg-buildpackage -us -uc -b -aarmhf
```

<br>

### 安装

```bash
sudo dpkg -i ../chsrc_*.deb
sudo apt-get install -f  # 修复依赖问题
```

<br>

### 测试安装情况

```bash
# 运行测试
bash ./deb-installation-test.sh

# 查看文档安装情况
man chsrc

# 查看 deb 包的 copyright
cat /usr/share/doc/chsrc/copyright

# 查看 deb 包 changelog
zless /usr/share/doc/chsrc/changelog.Debian.gz
```

<br>

### 清理构建产物

```bash
./Makefile deb-clean
```

<br>

## 卸载

```bash
sudo apt-get remove chsrc
```

包括删除配置在内的完全删除:

```bash
sudo apt-get purge chsrc
```

<br>


## 故障排查

常见问题:

1. **构建失败**: 检查 debian/control 中的依赖是否正确
2. **交叉编译失败**: 确认目标架构的工具链已正确安装
3. **安装测试失败**: 检查 postinst 脚本是否有错误

<br>


================================================
FILE: pkg/deb/CI.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : CI.md
 ! Doc Authors   : sanchuanhehe <wyihe5520@gmail.com>
 ! Contributors  :  曾奥然 <ccmywish@qq.com>
 !               |
 ! Created On    : <2025-06-14>
 ! Last Modified : <2025-06-16>
 ! ---------------------------------------------------------- -->

# deb package CI/CD

本文档说明了 chsrc 项目的 deb 包自动构建和发布流程。

## CI 文件

CI 维护者 [@sanchuanhehe](https://github.com/sanchuanhehe)

- [.github/workflows/pkg-deb.yml](../../.github/workflows/pkg-deb.yml)

<br>

## 支持的架构

当前支持以下架构的 deb 包构建:

- `amd64` (x86_64)

<br>

## CI 构建产物

每次 CI 构建会生成:

1. **deb 包文件**: `chsrc_<version>-1_<arch>.deb`
2. **仓库元数据**: `Packages` 和 `Packages.gz` 文件用于创建 APT 仓库

<br>


## 自动触发

deb 包构建 CI 会在以下情况下自动触发:

1. **Push 事件**:当 push 到 `gh-build` 分支时自动构建,并上传 deb 包 到 `pre` 这个特定的 release 中
2. **Release 事件**: 当创建新的 release 时自动构建,并上传 deb 包到最新的这个 release 中
2. **手动触发**: 可以在 GitHub Actions 页面手动触发构建

<br>

## 手动发布流程

1. 确保所有代码已合并到主分支
2. 更新版本号和 changelog
3. 创建并推送 git tag: `git tag v1.2.3 && git push origin v1.2.3`
4. 在 GitHub 上创建 release
5. CI 将自动构建并上传 deb 包

<br>


================================================
FILE: pkg/deb/Makefile
================================================
#!/usr/bin/make -f
# --------------------------------------------------------------
# SPDX-License-Identifier: GPL-3.0-or-later
# --------------------------------------------------------------
# Build File    : Makefile
# File Authors  : sanchuanhehe <wyihe5520@gmail.com>
# Contributors  :  曾奥然 <ccmywish@qq.com>
#								|
# Created On    : <2025-06-14>
# Last Modified : <2025-06-16>
#
# deb package targets
#
# @issue https://github.com/RubyMetric/chsrc/pull/206
# 这些本是 debhelper 兼容性版本 (debian/compat) 为 9 时所需要定义的 targets
# 然而现在已经为版本 13 (debian/compat已移除),不再需要这些 targets,仅出于
# 实用目的保留。由于以上原因,也不要修改这些 targets 的名称。
# --------------------------------------------------------------

all: deb-build

deb-prepare:
	@echo "Starting: Prepare for building deb package"
	@echo "Finished: Prepare for building deb package"

deb-build: deb-prepare
	@echo "Starting: Build deb package"
	@debuild -us -uc -b
	@echo "Finished: Build deb package"

deb-clean:
	@echo "Starting: Clean deb build artifacts"
	-@rm -rf debian/chsrc/
	-@rm -f ../chsrc_*.deb ../chsrc-dbgsym_*.ddeb ../chsrc_*.changes ../chsrc_*.buildinfo ../chsrc_*.build
	@echo "Finished: Clean deb build artifacts"

.PHONY: deb-prepare deb-build deb-clean


================================================
FILE: pkg/deb/README.md
================================================
<!-- -----------------------------------------------------------
 ! SPDX-License-Identifier: GFDL-1.3-or-later
 ! -------------------------------------------------------------
 ! Doc Type      : Markdown
 ! Doc Name      : README.md
 ! Doc Authors   : sanchuanhehe <wyihe5520@gmail.com>
 !               |  曾奥然 <ccmywish@qq.com>
 ! Contributors  : Nil Null <nil@null.org>
 !               |
 ! Created On    : <2025-06-14>
 ! Last Modified : <2025-06-16>
 ! ---------------------------------------------------------- -->

# deb package

本文档说明了 `chsrc` 项目的 deb 包的相关情况

<br>

## 相关文件

- `.github/workflows/pkg-deb.yml` - CI 配置文件
- `./CI.md` - CI 情况说明

<wbr>

- `./debian/` - deb 包构建配置目录
- `./BUILD.md` - 如何手动构建
- `./Makefile` - deb 包构建 Makefile
- `./deb-installation-test.sh` - deb 包 **已正确安装** 测试脚本

<br>


## 安装

如果你是普通用户,你应该从 [GitHub Releases](https://github.com/RubyMetric/chsrc/releases) 下载合适的 deb 包,然后运行以下命令安装:

```bash
sudo dpkg -i chsrc_*.deb
sudo apt-get install -f  # Fix any dependency issues
```

如果你是高级用户,你可以自己阅读本目录下的 [./BUILD.md](./BUILD.md) 来自己构建 deb 包并按照上述同样的方式安装。

<br>


## `debian/` 目录结构

```
debian/
├── changelog      # 版本更新日志
├── compat         # debhelper 兼容性版本
├── control        # 包控制信息和依赖
├── copyright      # 版权信息
├── postinst       # 安装后脚本
├── prerm          # 卸载前脚本
└── rules          # 构建规则
```

其中,最后三个是 `+x` 的可执行文件。

<br>


================================================
FILE: pkg/deb/deb-installation-test.sh
================================================
#!/bin/bash
# --------------------------------------------------------------
# SPDX-License-Identifier: GPL-3.0-or-later
# --------------------------------------------------------------
# Test File     : deb-installation-test.sh
# File Authors  : sanchuanhehe <wyihe5520@gmail.com>
# Contributors  :  曾奥然 <ccmywish@qq.com>
#               |
# Created On    : <2025-06-14>
# Last Modified : <2025-06-16>
#
# Test script for deb package installation
# --------------------------------------------------------------

set -e

echo "Testing installation of deb package 'chsrc' ..."

# Test 1: Check if chsrc binary exists and is executable
if [ ! -f "/usr/bin/chsrc" ]; then
  echo "ERROR: /usr/bin/chsrc not found"
  exit 1
fi

if [ ! -x "/usr/bin/chsrc" ]; then
  echo "ERROR: /usr/bin/chsrc is not executable"
  exit 1
fi

echo "✓ /usr/bin/chsrc binary exists and is executable"

# Test 2: Check if man page exists
if [ ! -f "/usr/share/man/man1/chsrc.1" ]; then
  echo "WARNING: chsrc man page not found at /usr/share/man/man1/chsrc.1"
else
  echo "✓ chsrc man page exists"
fi

# Test 3: Test basic functionality
echo "Testing basic chsrc functionality..."
if /usr/bin/chsrc help >/dev/null 2>&1; then
  echo "✓ command 'chsrc help' works"
else
  echo "ERROR: command 'chsrc help' failed"
  exit 1
fi

if /usr/bin/chsrc list >/dev/null 2>&1; then
  echo "✓ command 'chsrc list' works"
else
  echo "ERROR: command 'chsrc list' failed"
  exit 1
fi

echo "All installation tests of deb package 'chsrc' passed!"


================================================
FILE: pkg/deb/debian/changelog
================================================
chsrc (0.2.3-1) unstable; urgency=medium

  * v0.2.3 已发布

 -- 曾奥然 <ccmywish@qq.com>  Wed, 29 Oct 2025 11:29:05 +0800


chsrc (0.1.9-1) unstable; urgency=medium

  * v0.1.9 已发布

 -- 曾奥然 <ccmywish@qq.com>  Sun, 15 Jun 2025 13:32:50 +0800


chsrc (0.0.1-1) unstable; urgency=medium

  * 首个 deb 包已完成!

 -- sanchuanhehe <wyihe5520@gmail.com>  Mon, 10 Jun 2025 00:00:00 +0000


================================================
FILE: pkg/deb/debian/control
================================================
Source: chsrc
Section: utils
Priority: optional
Maintainer: sanchuanhehe <wyihe5520@gmail.com>
Build-Depends: debhelper-compat (= 13), build-essential, libc6-dev
Standards-Version: 4.6.0
Homepage: https://chsrc.run/
Vcs-Git: https://github.com/RubyMetric/chsrc.git
Vcs-Browser: https://github.com/RubyMetric/chsrc

Package: chsrc
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Change Source - A tool for changing software sources
 chsrc is a command-line tool for changing software sources (mirrors)
 for various package managers and programming language ecosystems.
 It supports automatic detection and switching of sources for better
 download speeds in different regions.


================================================
FILE: pkg/deb/debian/copyright
================================================
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: chsrc
Upstream-Contact: 曾奥然 <ccmywish@qq.com>
Source: https://github.com/RubyMetric/chsrc

Files: *
Copyright: 2023-2026 曾奥然 <ccmywish@qq.com>
           2023-2026  郭恒  <2085471348@qq.com>
License: GPL-3+
Comment: The authors' names are indicated in each source code file's header.

Files: lib/xy.h
Copyright: 2023-2026 曾奥然 <ccmywish@qq.com>
           2023-2026  郭恒  <2085471348@qq.com>
License: MIT

Files: pkg/deb/debian/*
Copyright: 2025-2026 sanchuanhehe <wyihe5520@gmail.com>
License: GPL-3+

License: GPL-3+
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 .
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 .
 You should have received a copy of the GNU General Public License
 along with this program. If not, see <https://www.gnu.org/licenses/>.
 .
 On Debian systems, the complete text of the GNU General
 Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
Comment:
 On Debian systems, the full text of the GNU General Public License
 version 3 can be found in the file '/usr/share/common-licenses/GPL-3'.

License: MIT
 MIT License

 Copyright (c) 2023-2026 曾奥然 (Aoran Zeng), 郭恒 (Heng Guo)

 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:

 The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.

 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.


================================================
FILE: pkg/deb/debian/postinst
================================================
#!/bin/sh
# --------------------------------------------------------------
# SPDX-License-Identifier: GPL-3.0-or-later
# --------------------------------------------------------------
# deb File      : postinst
# File Authors  : sanchuanhehe <wyihe5520@gmail.com>
# Contributors  :   Nil Null   <nil@null.org>
#	              |
# Created On    : <2025-06-14>
# Last Modified : <2025-06-16>
#
# postinst script for chsrc
# --------------------------------------------------------------

set -e

case "$1" in
    configure)
        # Update man database
        if command -v mandb >/dev/null 2>&1; then
            mandb -q /usr/share/man/man1/chsrc.1 2>/dev/null || true
        fi

        # Make sure chsrc is executable
        chmod +x /usr/bin/chsrc

        echo "chsrc has been successfully installed!"
        echo "Run 'chsrc help' to get started."
        ;;

    abort-upgrade|abort-remove|abort-deconfigure)
        ;;

    *)
        echo "postinst called with unknown argument \`$1'" >&2
        exit 1
        ;;
esac

#DEBHELPER#

exit 0


================================================
FILE: pkg/deb/debian/prerm
================================================
#!/bin/sh
# --------------------------------------------------------------
# SPDX-License-Identifier: GPL-3.0-or-later
# --------------------------------------------------------------
# deb File      : prerm
# File Authors  : sanchuanhehe <wyihe5520@gmail.com>
# Contributors  :   Nil Null   <nil@null.org>
#	              |
# Created On    : <2025-06-14>
# Last Modified : <2025-06-16>
#
# prerm script for chsrc
# --------------------------------------------------------------

set -e

case "$1" in
    remove|upgrade|deconfigure)
        # Nothing special to do during removal
        ;;

    failed-upgrade)
        ;;

    *)
        echo "prerm called with unknown argument \`$1'" >&2
        exit 1
        ;;
esac

#DEBHELPER#

exit 0


================================================
FILE: pkg/deb/debian/rules
================================================
#!/usr/bin/make -f
# --------------------------------------------------------------
# SPDX-License-Identifier: GPL-3.0-or-later
# --------------------------------------------------------------
# Build File    : rules
# File Authors  : sanchuanhehe <wyihe5520@gmail.com>
#               |  曾奥然 <ccmywish@qq.com>
# Contributors  : Nil Null <nil@null.org>
#								|
# Created On    : <2025-06-14>
# Last Modified : <2025-06-20>
#
# 该文件是 Makefile 格式
# --------------------------------------------------------------
#
# debuild 调用 dpkg-buildpackage
#
# dpkg-buildpackage 通过调用 fakeroot debian/rules <target> 执行本文件
#
# 由于下面的 %,所有任务都将被传递给 dh
#
# 比如:
#
# 	 debian/rules <target>
#
# 会转换为:
#
#			dh <target>
#
# 来执行
#
# 简单理解,将顺序调用:
#		1. dh clean
#		2. dh build  (debian/rules override_dh_auto_build)
#		3. dh binary (debian/rules override_dh_auto_install)
# --------------------------------------------------------------

# 由于 debuild 要寻找 debian/ 目录,因此当前工作目录一定在 pkg/deb 下
Chsrc-Root-Dir = $(CURDIR)/../../

%:
	dh $@

override_dh_auto_build:
# 切换到 chsrc 根目录
	@$(MAKE) -C $(Chsrc-Root-Dir) build-in-release-mode

override_dh_auto_install:
	@$(MAKE) -C $(Chsrc-Root-Dir) install DESTDIR=$(CURDIR)/debian/chsrc


================================================
FILE: src/chsrc-main.c
================================================
/** ------------------------------------------------------------
 * Copyright © 2023-2026 曾奥然, 郭恒
 * SPDX-License-Identifier: GPL-3.0-or-later
 * -------------------------------------------------------------
 *
 *                  chsrc: Change Source
 *
 *                 全平台通用换源工具与框架
 *
 *         Change Source everywhere for every software
 *
 * 项目创建者: 曾奥然, 郭恒
 * -------------------------------------------------------------
 *
 * 这是一个高度依靠贡献者的项目,我们直接把每一位贡献者写进了代码
 * 里,这是比 Git commit message 更加稳定的方式。但我们不满足于仅
 * 把大家写在注释里,因为C语言在编译时会无情地把这些信息抹去。
 *
 *           所以,我们让每一位贡献者直接参与运行时!
 *
 * 想象一下,每一位贡献者都化作一串比特,穿梭于全国各地的桌面PC中,
 * 流淌在数据中心的机房,分身在手机、路由器、小型嵌入式设备中...
 * 每当 chsrc 执行一次 recipe 相关的操作,这些比特便会复苏,贡献者
 * 的信息随之浮现。它提醒着使用者:在你与开源世界的每一次交互背后,
 * 都是许多人的协作,跨越省份与疆域,以代码相连。
 *
 * 我们希望营造像 Richard Stallman 在创建 GNU 项目之前,在 MIT 时
 * 那样的氛围 —— 写自己用得上的软件,与大家一起开发、维护,简单纯
 * 粹,无关商业利益。就像小区、校园自发组建的足球篮球队,从一次偶
 * 然的加入,逐渐成长为互相支持的伙伴。
 * ------------------------------------------------------------*/

#define Chsrc_Maintain_URL   "https://github.com/RubyMetric/chsrc"
#define Chsrc_Maintain_URL2  "https://gitee.com/RubyMetric/chsrc"

#include "framework/version.h"
#include "framework/core.c"
#include "framework/chef.c"

void
chsrc_register_contributors ()
{
  /* 项目创建者 */
  chef_register_contributor ("@ccmywish",       "曾奥然",         "ccmywish@qq.com",                NULL);
  // 该 ID 为 Gitee ID
  chef_register_contributor ("@G_I_Y",          "郭恒",           "2085471348@qq.com",              NULL);

  /* 所有贡献者 (按参与贡献时间排序) */
  chef_register_contributor ("@Aaron-212",      "Aaron Ruan",     "aaron212cn@outlook.com",         NULL);
  chef_register_contributor ("@chenrui333",     "Rui Chen",       "rui@chenrui.dev",                NULL);
  chef_register_contributor ("@livelycode36",   "Shengwei Chen",  "414685209@qq.com",               NULL);
  chef_register_contributor ("@Gn3po4g",        "Peng Gao",       "gn3po4g@outlook.com",            NULL);
  chef_register_contributor ("@BlockLune",      "BlockLune",      "blocklune@gmail.com",            NULL);
  chef_register_contributor ("@MrWillCom",      "Mr. Will",       "mr.will.com@outlook.com",        NULL);
  chef_register_contributor ("@Jerry-Terrasse", "Terrasse",       "terrasse@qq.com",                NULL);
  chef_register_contributor ("@lontten",        "Lontten",        "lontten@163.com",                NULL);
  chef_register_contributor ("@happy-game",     "Happy Game",     "happygame1024@gmail.com",        NULL);
  chef_register_contributor ("@Word2VecT",      "Word2VecT",      "tangzinan@bupt.edu.cn",          NULL);
  chef_register_contributor ("@wickdynex",      "Xuan",           "wick.dynex@qq.com",              NULL);
  chef_register_contributor ("@Efterklang",     "GnixAij",        "gaojiaxing0220@gmail.com",       NULL);
  chef_register_contributor ("@czyt",           "czyt",           "czyt.go@gmail.com",              NULL);
  chef_register_contributor ("@XUANJI233",      "XUANJI233",      "xuanji233@outlook.com",          NULL);
  chef_register_contributor ("@Yangmoooo",      "Yangmoooo",      "yangmoooo@outlook.com",          NULL);
  chef_register_contributor ("@zouri",          "Zouri",          "guoshuaisun@outlook.com",        NULL);
  chef_register_contributor ("@xyx1926885268",  "Yongxiang",      "1926885268@qq.com",              NULL);
  chef_register_contributor ("@YU-7",           "YU-7",           "2747046473@qq.com",              NULL);
  chef_register_contributor ("@juzeon",         "juzeon",         "skyjuzheng@gmail.com",           NULL);
  chef_register_contributor ("@jialinlvcn",     "Jialin Lyu",     "jialinlvcn@aliyun.com",          NULL);
  chef_register_contributor ("@Kattos",         "ccy",            "icuichengyi@gmail.com",          NULL);
  chef_register_contributor ("@xrgzs",          "MadDogOwner",    "xiaoran@xrgzs.top",              NULL);
  chef_register_contributor ("@sanchuanhehe",   "sanchuanhehe",   "wyihe5520@gmail.com",            NULL);
  chef_register_contributor ("@Mikachu2333",    "Mikachu2333",    "mikachu.23333@zohomail.com",     NULL);
  chef_register_contributor ("@techoc",         "Rui Yang",       "techoc@foxmail.com",             NULL);
  chef_register_contributor ("@BingChunMoLi",   "BingChunMoLi",   "bingchunmoli@bingchunmoli.com",  NULL);
  // 该 ID 为 Gitee ID
  chef_register_contributor ("@hezonglun",      "HeZongLun",      "hezonglun123456@outlook.com",    NULL);
  chef_register_contributor ("@Young-Lord",     "LY",             "ly-niko@qq.com",                 NULL);
  chef_register_contributor ("@MingriLingran",  "MingriLingran",  "i@linran.moe",                   NULL);
  chef_register_contributor ("@usernameisnull", "MaBing",         "cumt_ttr@163.com",               NULL);

  /**
   * AI贡献者:
   *
   *    ChatGPT、GitHub Copilot、DeepSeek
   *
   * 这几位是贡献者显式说明的,也许还有隐式使用的一些AI并没有被记录下来,可以添加在这里
   */
}

#include "recipe/menu.c"

#include "rawstr4c.h"



void
cli_print_available_mirrors ()
{
  {
  char *msg = ENGLISH ? "To specify a source, use chsrc set " : "指定使用某源,请使用 chsrc set ";
  say (bdblue(xy_strcat (3, msg, "<target>", " <code>\n")));
  }

  {
  char *msg = ENGLISH ? "Available Mirror Sites: \n" : "可用镜像站: \n";
  say (bdgreen(msg));
  }

  {
  char *msg1 = ENGLISH ? "Mirror abbr" : "镜像站简写";
  char *msg2 = ENGLISH ? "Mirror URL"  : "镜像站URL";
  char *msg3 = ENGLISH ? "Mirror Name" : "镜像站";
  char *format = ENGLISH ? "  %-13s%-28s%-35s%s\n" : "  %-13s%-33s%-42s%s\n";
  printf (format, "code", msg1, msg2, msg3);
  say    ("---------    --------------    -------------------------------------     ---------------------");
  }

  for (int i = 0; i < xy_c_array_len (chsrc_available_mirrors); i++)
    {
      MirrorSite_t *mir = chsrc_available_mirrors[i];
      printf ("%-14s%-18s%-41s ", mir->code, mir->abbr, mir->site); say (mir->name);
    }
}


/**
 * @brief 遍历以 / 为分隔符的别名字符串,对每个别名调用回调函数
 *
 * @param  aliases    空格分隔的 alias 字符串
 * @param  callback   对每个 alias 调用的回调函数
 * @param  user_data  传递给回调函数的用户数据
 *
 * @return 如果回调函数返回true则停止遍历并返回true,否则返回false
 */
bool
iterate_aliases (const char *aliases, bool (*callback)(const char *alias, void *user_data), void *user_data)
{
  char *aliases_copy = xy_strdup (aliases);
  char *tok_start = aliases_copy;
  char *cursor;
  bool result = false;

  while (*tok_start != '\0')
    {
      cursor = tok_start;
      while (*cursor != '/' && *cursor != '\0') cursor++;

      // 结束当前token
      char space_or_eos = *cursor;
      *cursor = '\0';

      // 调用回调函数
      if (callback(tok_start, user_data))
        {
          result = true;
          break;
        }

      *cursor = space_or_eos;
      if (space_or_eos == '\0') { break; }
      tok_start = cursor+1;
    }

  return result;
}


/**
 * 用于 cli_print_targets_for_menu 的回调函数,打印每个别名
 */
bool
callback_print_alias (const char *alias, void *user_data)
{
  printf ("%s  ", alias);
  return false; // 继续遍历,不停止
}

void
callback_print_targets (void *data, void *DUMMY)
{
  Target_t *target = (Target_t *) data;
  // 使用通用的别名遍历函数打印所有别名
  iterate_aliases (target->aliases, callback_print_alias, NULL);
  br(); // 每个target换行
}

void
cli_print_targets_for_menu (XySeq_t *menu)
{
  xy_seq_each (menu, callback_print_targets, NULL);
  br(); // 最后额外换行
}

void
cli_print_supported_targets ()
{
  {
  char *msg = ENGLISH ? "Support following targets (same line indicates these targets are compatible)"
                      : "支持对以下目标换源 (同一行表示这几个命令兼容)" ;
  say (bdblue(msg)); br();
  }

  {
  char *msg = ENGLISH ? "Programming Languages" : "编程语言";
  say (bdgreen(msg));
  say ("-------------------------");
  cli_print_targets_for_menu (ProgStore.pl);
  }

  {
  char *msg = ENGLISH ? "Operating Systems" : "操作系统";
  say (bdgreen(msg));
  say ("-------------------------");
  cli_print_targets_for_menu (ProgStore.os);
  }

  {
  char *msg = ENGLISH ? "Softwares" : "软件";
  say (bdgreen(msg));
  say ("-------------------------");
  cli_print_targets_for_menu (ProgStore.wr);
  }
}

void
cli_print_menu (char *menu)
{
  if (xy_streql (menu, "pl"))
    {
      char *msg =
        ENGLISH ? "Support following Programming Languages (same line indicates these targets are compatible)\n"
                : "支持对以下编程语言生态换源 (同一行表示这几个目标兼容)\n";
      say (bdgreen(msg));
      cli_print_targets_for_menu (ProgStore.pl);
    }
  else if (xy_streql (menu, "os"))
    {
      char *msg =
        ENGLISH ? "Support following Operating Systems (same line indicates these targets are compatible)\n"
                : "支持对以下操作系统换源 (同一行表示这几个目标兼容)\n";
      say (bdgreen(msg));
      cli_print_targets_for_menu (ProgStore.os);
    }
  else if (xy_streql (menu, "wr"))
    {
      char *msg =
        ENGLISH ? "Support following Softwares (same line indicates these targets are compatible)\n"
                : "支持对以下软件换源 (同一行表示这几个目标兼容)\n";
      say (bdgreen(msg));
      cli_print_targets_for_menu (ProgStore.wr);
    }
}



/**
 * 用于 chsrc list <target>
 */
void
cli_print_target_available_sources (Source_t sources[], size_t size)
{
  for (int i=0;i<size;i++)
    {
      Source_t src = sources[i];
      const MirrorSite_t *mir = src.mirror;
      if (NULL == src.url)
        {
          src.url = "Please help to add the upstream url!";
        }
      printf ("%-14s%-18s%-50s ", mir->code, mir->abbr, src.url);
      say (mir->name);
    }
}


void
cli_print_target_features (Target_t *target, const char *input_target_name)
{
  {
  char *msg = ENGLISH ? "\nAvailable Features:\n" : "\n可用功能:\n";
  say (bdgreen(msg));
  }

  {
  char *msg = ENGLISH ? " Get: View the current source state " : " Get: 查看当前源状态 ";
  char *get_msg = xy_strcat (3, msg, "| chsrc get ", input_target_name);
  if (target->getfn != NULL) printf (" %s%s\n", bdgreen(YesMark), purple(get_msg));
  else printf (" %s%s\n", bdred(NoMark), get_msg);br();
  }

  {
  char *msg = ENGLISH ? " Reset: Reset to the default source " : " Reset: 重置回默认源 ";
  char *reset_msg = xy_strcat (3, msg, "| chsrc reset ", input_target_name);
  if (target->resetfn != NULL) printf (" %s%s\n", bdgreen(YesMark), purple(reset_msg));
  else printf (" %s%s\n", bdred(NoMark), reset_msg);br();
  }

  {
  char *msg = ENGLISH ? " UserDefine: using user-defined source link " : " UserDefine: 用户自定义换源链接 ";
  char *user_define_msg = xy_strcat (5, msg, "| chsrc set ", input_target_name, " https://user-define-url.org/", input_target_name);
  if (target->can_user_define) printf (" %s%s\n", bdgreen(YesMark), purple(user_define_msg));
  else printf (" %s%s\n", bdred(NoMark), user_define_msg);br();
  }

  {
  char *scope_msg = NULL;

  for (int i=0; i<NumberOfScopeType; i++)
    {
      ScopeCapability_t cap = target->scope_caps[i];
      char *scope_name;
      if (i == 0)
        {
          scope_name = CHINESE ? " 项目级换源" : " project scope";
          scope_msg = xy_strcat (3, scope_name, " | chsrc set -scope=project ", input_target_name);
        }
      else if (i == 1)
        {
          scope_name = CHINESE ? " 用户级换源" : " user scope";
          scope_msg = xy_strcat (3, scope_name, " | chsrc set -scope=user    ", input_target_name);
        }
      else if (i == 2)
        {
          scope_name = CHINESE ? " 系统级换源" : " system scope";
          scope_msg = xy_strcat (3, scope_name, " | chsrc set -scope=system  ", input_target_name);
        }
      else
        {
          xy_unreached();
        }

      char *msg = NULL;
      switch (cap)
        {
        case ScopeCap_Unknown:
          msg = xy_strcat (6, " ", bdred(NoMark), scope_msg, " (", "是否支持该作用域尚不了解,欢迎贡献", ")");
          puts (msg);
          break;
        case ScopeCap_Unable:
          msg = xy_strcat (6, " ", bdred(NoMark), scope_msg, " (", "不支持", ")");
          puts (msg);
          break;
        case ScopeCap_Able_But_Not_Implemented:
          msg = xy_strcat (6, " ", bdyellow(HalfYesMark), scope_msg, " (", "支持但未实现", ")");
          puts (msg);
          break;
        case ScopeCap_Able_And_Implemented:
          msg = xy_strcat (3, " ", bdgreen(YesMark),
            purple (xy_strcat (4, scope_msg, " (", "支持且已实现", ")")));
          puts (msg);
          break;
        default:
          xy_unreached();
        }
    }
    Scope_t default_scope = target->default_scope;
    char *default_scope_name = NULL;
    switch (default_scope)
      {
      case ProjectScope:
        default_scope_name = CHINESE ? "项目级" : "Project Scope";
        break;
      case UserScope:
        default_scope_name = CHINESE ? "用户级" : "User Scope";
        break;
      case SystemScope:
        default_scope_name = CHINESE ? "系统级" : "System Scope";
        break;
      case ImplementationDefinedScope:
        default_scope_name = CHINESE ? "由实现定义" : "Implementation Defined Scope";
        break;
      default:
        xy_unreached();
      }
    char *msg = xy_strcat (3, bdblue (" = "),
      purple (xy_strcat (5, "默认作用域 | chsrc set -scope=default ", input_target_name, " (= ", default_scope_name ,")")));
    puts (msg);
    br();
  }

  {
  char *msg = ENGLISH ? " English: Output in English " : " English: 英文输出 ";
  char *english_msg = xy_strcat (3, msg, "| chsrc set -en ", input_target_name);
  if (target->can_english) printf (" %s%s\n", bdgreen(YesMark), purple(english_msg));
  else printf (" %s%s\n", bdred(NoMark), english_msg);br();
  }

  if (target->note)
    {
      char *msg = ENGLISH ? "NOTE: " : "备注: ";
      printf ("%s%s\n\n", bdyellow (msg), bdyellow (target->note));
    }
}


/**
 * @brief 简略打印维护信息
 *
 * 用于 chsrc get/set/reset <target>
 */
void
cli_print_target_maintain_info_briefly (Target_t *target, const char *input_target_name)
{
  if (target->sources_last_updated)
    {
      char *msg = ENGLISH ? "Ingredient(Sources) Last Updated: " : "食源检查: ";
      printf ("%s%s  ", msg, purple(target->sources_last_updated));
    }

  if (target->last_updated)
    {
      char *msg = ENGLISH ? "Recipe Last Updated: " : "食谱更新: ";
      printf ("%s%s  ", msg, purple(target->last_updated));
    }

  char num[32]; sprintf(num, "%d", target->cooks_n + target->sauciers_n);
  char *msg = ENGLISH ? "Contributors: " : "后厨人数: ";
  printf ("%s%s  ", msg, purple(num));

  msg = ENGLISH ? xy_strcat (3, "(See chsrc ls ",  input_target_name, ")")
                : xy_strcat (3, "(详查 chsrc ls ", input_target_name, ")");
  printf ("%s\n", msg);
}


/**
 * @brief 详细打印维护信息
 *
 * 用于 chsrc ls <target>
 */
void
cli_print_target_maintain_info (Target_t *target, const char *input_target_name)
{
  if (ta
Download .txt
gitextract_0jn8y55u/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── 01-Report_Bug.yml
│   │   ├── 02-Request_Recipe.yml
│   │   ├── 03-Share.yml
│   │   ├── 04-Deprecate.yml
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE/
│   │   ├── Add_Feature.md
│   │   ├── Clean.md
│   │   ├── Enhance.md
│   │   ├── Fix_Bug.md
│   │   ├── Implement.md
│   │   ├── Refactor.md
│   │   └── Relate_Mirror_Source.md
│   ├── READIT.md
│   ├── copilot-instructions.md
│   ├── dependabot.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── PR-notify.yml
│       ├── PR-test.yml
│       ├── build-on-Linux-AArch64.yml
│       ├── build-on-Linux-ARMv7.yml
│       ├── build-on-Linux-riscv64.yml
│       ├── build-on-Linux-x64.yml
│       ├── build-on-Windows.yml
│       ├── build-on-macOS.yml
│       ├── pkg-deb.yml
│       ├── pub-AUR-chsrc-and-chsrc-bin.yml
│       ├── pub-AUR-chsrc-git.yml
│       └── pub-WinGet.yml
├── .gitignore
├── .vscode/
│   ├── README.md
│   ├── c_cpp_properties.json
│   ├── extensions.json
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── COPYING
├── LICENSE-MIT.txt
├── Makefile
├── README.md
├── bootstrap/
│   ├── README.md
│   └── Termux.bash
├── doc/
│   ├── 01-开发与构建.md
│   ├── 02-提交与贡献.md
│   ├── 03-为什么拒绝使用代码格式化工具.md
│   ├── 10-如何编写recipe.md
│   ├── 11-如何设置换源链接与测速链接.md
│   ├── 50-协作者与维护者.md
│   ├── README.md
│   ├── chsrc.1
│   └── chsrc.texi
├── include/
│   └── .keep
├── justfile
├── lefthook.yml
├── lib/
│   └── xy.h
├── pkg/
│   ├── AUR/
│   │   └── README.md
│   ├── README.md
│   └── deb/
│       ├── BUILD.md
│       ├── CI.md
│       ├── Makefile
│       ├── README.md
│       ├── deb-installation-test.sh
│       └── debian/
│           ├── changelog
│           ├── control
│           ├── copyright
│           ├── postinst
│           ├── prerm
│           └── rules
├── src/
│   ├── chsrc-main.c
│   ├── framework/
│   │   ├── chef.c
│   │   ├── core.c
│   │   ├── helper.c
│   │   ├── mirror.c
│   │   ├── struct.h
│   │   └── version.h
│   ├── rawstr4c.h
│   ├── rawstr4c.md
│   ├── recipe/
│   │   ├── lang/
│   │   │   ├── Clojure.c
│   │   │   ├── Dart/
│   │   │   │   ├── Flutter.c
│   │   │   │   ├── Pub.c
│   │   │   │   └── common.h
│   │   │   ├── Go.c
│   │   │   ├── Haskell.c
│   │   │   ├── Java.c
│   │   │   ├── JavaScript/
│   │   │   │   ├── Bun.c
│   │   │   │   ├── JavaScript.c
│   │   │   │   ├── Yarn.c
│   │   │   │   ├── common.h
│   │   │   │   ├── npm.c
│   │   │   │   ├── nvm.c
│   │   │   │   └── pnpm.c
│   │   │   ├── Julia.c
│   │   │   ├── Lua.c
│   │   │   ├── NuGet.c
│   │   │   ├── OCaml.c
│   │   │   ├── PHP.c
│   │   │   ├── Perl.c
│   │   │   ├── Python/
│   │   │   │   ├── PDM.c
│   │   │   │   ├── Poetry.c
│   │   │   │   ├── Python.c
│   │   │   │   ├── Rye.c
│   │   │   │   ├── common.h
│   │   │   │   ├── pip.c
│   │   │   │   ├── rawstr4c.h
│   │   │   │   ├── rawstr4c.md
│   │   │   │   └── uv.c
│   │   │   ├── R.c
│   │   │   ├── Ruby/
│   │   │   │   ├── README.md
│   │   │   │   └── Ruby.c
│   │   │   ├── Rust/
│   │   │   │   ├── Cargo.c
│   │   │   │   ├── common.h
│   │   │   │   └── rustup.c
│   │   │   ├── rawstr4c.h
│   │   │   └── rawstr4c.md
│   │   ├── menu.c
│   │   ├── os/
│   │   │   ├── APT/
│   │   │   │   ├── Armbian.c
│   │   │   │   ├── Debian.c
│   │   │   │   ├── Kali-Linux.c
│   │   │   │   ├── Linux-Lite.c
│   │   │   │   ├── Linux-Mint.c
│   │   │   │   ├── ROS.c
│   │   │   │   ├── Raspberry-Pi-OS.c
│   │   │   │   ├── Termux.c
│   │   │   │   ├── Trisquel.c
│   │   │   │   ├── Ubuntu.c
│   │   │   │   ├── common.h
│   │   │   │   ├── deepin.c
│   │   │   │   ├── openKylin.c
│   │   │   │   ├── rawstr4c.h
│   │   │   │   └── rawstr4c.md
│   │   │   ├── Alpine-Linux.c
│   │   │   ├── BSD/
│   │   │   │   ├── FreeBSD.c
│   │   │   │   ├── NetBSD.c
│   │   │   │   └── OpenBSD.c
│   │   │   ├── Gentoo-Linux.c
│   │   │   ├── OpenWrt.c
│   │   │   ├── Solus.c
│   │   │   ├── Void-Linux.c
│   │   │   ├── YUM/
│   │   │   │   ├── AlmaLinux.c
│   │   │   │   ├── Anolis-OS.c
│   │   │   │   ├── Fedora-Linux.c
│   │   │   │   ├── Rocky-Linux.c
│   │   │   │   ├── common.h
│   │   │   │   └── openEuler.c
│   │   │   ├── openSUSE.c
│   │   │   ├── pacman/
│   │   │   │   ├── Arch-Linux.c
│   │   │   │   ├── MSYS2.c
│   │   │   │   └── Manjaro-Linux.c
│   │   │   ├── rawstr4c.h
│   │   │   └── rawstr4c.md
│   │   ├── recipe-template.c
│   │   └── ware/
│   │       ├── Anaconda/
│   │       │   ├── Anaconda.c
│   │       │   ├── rawstr4c.h
│   │       │   └── rawstr4c.md
│   │       ├── CocoaPods.c
│   │       ├── Docker/
│   │       │   ├── Docker.c
│   │       │   ├── README.md
│   │       │   ├── rawstr4c.h
│   │       │   └── rawstr4c.md
│   │       ├── Emacs.c
│   │       ├── Flatpak.c
│   │       ├── Guix.c
│   │       ├── Homebrew/
│   │       │   ├── Homebrew.c
│   │       │   ├── rawstr4c.h
│   │       │   └── rawstr4c.md
│   │       ├── Nix.c
│   │       ├── TeX-Live.c
│   │       └── WinGet.c
│   └── resource/
│       └── chsrc.rc
├── test/
│   ├── cli.pl
│   ├── fw.c
│   └── xy.c
└── tool/
    ├── README.md
    ├── download-pre-on-GitHub.ps1
    ├── git-ignore-vscode-settings.ps1
    ├── installer.ps1
    └── installer.sh
Download .txt
SYMBOL INDEX (391 symbols across 80 files)

FILE: lib/xy.h
  function _xy_internal_warn (line 148) | static inline void
  function _xy_print_int (line 154) | static void _xy_print_int    (int n) {printf ("%d", n);}
  function _xy_print_long (line 155) | static void _xy_print_long   (long n) {printf ("%ld", n);}
  function _xy_print_long_long (line 156) | static void _xy_print_long_long (long long n) {printf ("%lld", n);}
  function _xy_print_float (line 157) | static void _xy_print_float  (float n) {printf ("%f", n);}
  function _xy_print_double (line 158) | static void _xy_print_double (double n) {printf ("%f", n);}
  function _xy_print_bool (line 159) | static void _xy_print_bool   (bool b) {printf("%s", (b) ? "true" : "fals...
  function _xy_print_str (line 160) | static void _xy_print_str    (char *str) {printf ("%s", str);}
  function _xy_print_const_str (line 161) | static void _xy_print_const_str (const char *str) {printf ("%s", str);}
  function _xy_println_int (line 163) | static void _xy_println_int    (int n) {printf ("%d\n", n);}
  function _xy_println_long (line 164) | static void _xy_println_long   (long n) {printf ("%ld\n", n);}
  function _xy_println_long_long (line 165) | static void _xy_println_long_long (long long n) {printf ("%lld\n", n);}
  function _xy_println_float (line 166) | static void _xy_println_float  (float n) {printf ("%f\n", n);}
  function _xy_println_double (line 167) | static void _xy_println_double (double n) {printf ("%f\n", n);}
  function _xy_println_bool (line 168) | static void _xy_println_bool   (bool b) {printf("%s\n", (b) ? "true" : "...
  function _xy_println_str (line 169) | static void _xy_println_str    (char *str) {printf ("%s\n", str);}
  function _xy_println_const_str (line 170) | static void _xy_println_const_str (const char *str) {printf ("%s\n", str);}
  function br (line 208) | void br ()                   { puts (""); }
  function p (line 209) | void p (const char *s)       { printf ("%s\n", s); }
  function xy_ptr_replace (line 231) | static inline void
  function xy_streql (line 498) | static bool
  function xy_streql_ic (line 508) | static bool
  function xy_str_end_with (line 537) | static bool
  function xy_str_start_with (line 564) | static bool
  type XyStrFindResult_t (line 655) | typedef struct
  function XyStrFindResult_t (line 666) | static XyStrFindResult_t
  function _xy_log (line 791) | static void
  function xy_log_brkt_to (line 856) | static void
  function _xy_log_brkt (line 870) | static void
  function xy_run_get_status (line 1015) | int
  function xy_run_get_stdout (line 1034) | static int
  function xy_file_exist (line 1174) | static bool
  function xy_dir_exist (line 1196) | static bool
  function _xy_detect_os (line 1318) | void
  function xy_use_utf8 (line 1418) | void
  function xy_init (line 1430) | void
  type XySeqItem_t (line 1449) | typedef struct XySeqItem_t
  type XySeq_t (line 1458) | typedef struct XySeq_t
  function XySeq_t (line 1468) | XySeq_t*
  function xy_seq_len (line 1484) | uint32_t
  function xy_seq_push (line 1539) | void
  function xy_seq_each (line 1599) | void
  type _XyHashBucket_t (line 1634) | struct _XyHashBucket_t
  type XyMap_t (line 1641) | typedef struct XyMap_t
  function XyMap_t (line 1650) | XyMap_t *
  function xy_map_len (line 1662) | uint32_t
  function xy_hash (line 1670) | unsigned long
  function xy_map_set (line 1684) | void
  type _XyHashBucket_t (line 1729) | struct _XyHashBucket_t
  function xy_map_each (line 1745) | void

FILE: src/chsrc-main.c
  function chsrc_register_contributors (line 40) | void
  function cli_print_available_mirrors (line 96) | void
  function iterate_aliases (line 135) | bool
  function callback_print_alias (line 171) | bool
  function callback_print_targets (line 178) | void
  function cli_print_targets_for_menu (line 187) | void
  function cli_print_supported_targets (line 194) | void
  function cli_print_menu (line 225) | void
  function cli_print_target_available_sources (line 259) | void
  function cli_print_target_features (line 276) | void
  function cli_print_target_maintain_info_briefly (line 401) | void
  function cli_print_target_maintain_info (line 431) | void
  function cli_print_version (line 510) | void
  function cli_print_help (line 521) | void
  function cli_print_issues (line 533) | void
  function callback_match_alias (line 551) | bool
  function callback_is_one_of_target_aliases (line 561) | bool
  function iterate_menu (line 584) | bool
  function callback_perform_all_prelude_for_menu (line 603) | void
  function chsrc_perform_all_prelude (line 623) | void
  function chsrc_op_epilogue (line 636) | void
  type TargetOp (line 645) | typedef enum {
  function get_target (line 662) | bool
  function main (line 759) | int

FILE: src/framework/chef.c
  function chef_debug_target (line 15) | void
  function chef_debug_contributor (line 47) | void
  function chef_register_contributor (line 72) | void
  function chef_set_provider_smURL (line 97) | void
  function chef_set_provider_sm_accuracy (line 111) | void
  function chef_set_repoURL (line 124) | void
  function chef_set_smURL_with_func (line 149) | void
  function chef_set_smURL_with_postfix (line 185) | void
  function chef_set_smURL (line 204) | void
  function chef_set_rest_smURL_with_func (line 214) | void
  function chef_set_rest_smURL_with_postfix (line 244) | void
  function chef_use_other_target_sources (line 254) | void
  function chef_allow_english (line 273) | void
  function chef_deny_english (line 280) | void
  function chef_set_scope_cap (line 291) | void
  function chef_set_default_scope (line 321) | void
  function chef_set_os_scope (line 356) | void
  function chef_allow_user_define (line 370) | void
  function chef_deny_user_define (line 379) | void
  function chef_set_note (line 392) | void
  function Contributor_t (line 408) | Contributor_t *
  function chef_set_chef (line 427) | void
  function chef_set_cooks (line 447) | void
  function chef_set_sauciers (line 473) | void
  function chef_set_recipe_created_on (line 500) | void
  function chef_set_recipe_last_updated (line 510) | void
  function chef_set_sources_last_updated (line 520) | void
  function chef_set_user_agent (line 535) | void

FILE: src/framework/core.c
  function chsrc_in_target_group_mode (line 67) | bool chsrc_in_target_group_mode() {return ProgMode.TargetGroupMode;}
  function chsrc_in_standalone_mode (line 69) | bool chsrc_in_standalone_mode() {return !ProgMode.TargetGroupMode;}
  function chsrc_set_target_group_mode (line 70) | void chsrc_set_target_group_mode(){ProgMode.TargetGroupMode = true;}
  function chsrc_in_reset_mode (line 72) | bool chsrc_in_reset_mode(){return ProgMode.ResetMode;}
  function chsrc_in_default_scope_mode (line 74) | bool chsrc_in_default_scope_mode(){return ProgMode.Scope == Implementati...
  function chsrc_in_user_scope_mode (line 75) | bool chsrc_in_user_scope_mode(){return ProgMode.Scope == UserScope;}
  function chsrc_in_project_scope_mode (line 76) | bool chsrc_in_project_scope_mode(){return ProgMode.Scope == ProjectScope;}
  function chsrc_in_system_scope_mode (line 77) | bool chsrc_in_system_scope_mode(){return ProgMode.Scope == SystemScope;}
  function chsrc_in_english_mode (line 79) | bool chsrc_in_english_mode(){return ProgMode.EnglishMode;}
  function chsrc_in_no_color_mode (line 80) | bool chsrc_in_no_color_mode(){return ProgMode.NoColorMode;}
  function in_measure_mode (line 87) | static bool in_measure_mode(){return ProgMode.MeasureMode;}
  function in_ipv6_mode (line 88) | static bool in_ipv6_mode(){return ProgMode.Ipv6Mode;}
  function in_dry_run_mode (line 89) | static bool in_dry_run_mode(){return ProgMode.DryRunMode;}
  type ChgType_t (line 102) | typedef enum ChgType_t
  function chsrc_note2 (line 198) | void
  function chsrc_alert2 (line 208) | void
  function chsrc_init_framework (line 217) | void
  function chsrc_log_write (line 230) | void
  function chsrc_log_backup (line 238) | void
  function log_check_result (line 252) | static void
  function log_cmd_result (line 286) | static void
  function query_program_exist (line 343) | bool
  function chsrc_check_program (line 416) | bool
  function chsrc_check_program_quietly (line 429) | bool
  function chsrc_check_program_quietly_when_exist (line 441) | bool
  function chsrc_ensure_program (line 456) | void
  function chsrc_check_file (line 474) | bool
  function query_mirror_exist (line 499) | int
  function parse_and_say_curl_result (line 660) | double
  function get_max_ele_idx_in_dbl_ary (line 685) | int
  function measure_speed_for_every_source (line 708) | void
  function auto_select_mirror (line 870) | int
  function use_specific_mirror_or_auto_select (line 975) | int
  function source_is_upstream (line 989) | bool
  function source_is_userdefine (line 995) | bool
  function source_has_empty_url (line 1001) | bool
  function Source_t (line 1025) | Source_t
  function chsrc_confirm_source (line 1071) | void
  function Source_t (line 1101) | Source_t
  function chsrc_determine_chgtype (line 1110) | void
  function chsrc_conclude (line 1145) | void
  function chsrc_check_scope_capability (line 1269) | void
  function chsrc_ensure_root (line 1321) | void
  function chsrc_run (line 1351) | static void
  function chsrc_run_as_a_service (line 1399) | static void
  function chsrc_run_directly (line 1416) | int
  function FILE (line 1443) | FILE *
  function chsrc_run_as_bash_file (line 1555) | void
  function chsrc_run_as_sh_file (line 1576) | void
  function chsrc_run_as_pwsh_file (line 1597) | void
  function chsrc_run_as_powershellv5_file (line 1617) | void
  function chsrc_run_as_powershell_file (line 1638) | void
  function chsrc_run_in_inline_bash_shell (line 1661) | void
  function chsrc_run_in_inline_pwsh_shell (line 1675) | void
  function chsrc_view_env (line 1683) | static void
  function chsrc_view_file (line 1742) | static void
  function chsrc_ensure_dir (line 1759) | static void
  function chsrc_append_to_file (line 1789) | static void
  function chsrc_prepend_to_file (line 1844) | static void
  function chsrc_overwrite_file (line 1875) | static void
  function chsrc_backup (line 1914) | static void
  function chsrc_get_cpucore (line 2031) | static int

FILE: src/framework/helper.c
  function hp_is_url (line 14) | bool

FILE: src/framework/struct.h
  type ProviderSpeedMeasureInfo_t (line 15) | typedef struct ProviderSpeedMeasureInfo_t
  type ProviderType_t (line 33) | typedef enum ProviderType_t
  type SourceProvider_t (line 42) | typedef struct SourceProvider_t
  type SourceProvider_t (line 53) | typedef SourceProvider_t MirrorSite_t;
  type Source_t (line 74) | typedef struct Source_t
  type Scope_t (line 122) | typedef enum Scope_t
  type ScopeCapability_t (line 140) | typedef enum ScopeCapability_t
  type Capability_t (line 149) | typedef enum Capability_t
  type Contributor_t (line 159) | typedef struct Contributor_t
  type Target_t (line 169) | typedef struct Target_t

FILE: src/recipe/lang/Clojure.c
  function pl_clojure_prelude (line 7) | void

FILE: src/recipe/lang/Dart/Flutter.c
  function pl_dart_flutter_prelude (line 7) | void
  function pl_dart_flutter_getsrc (line 43) | void
  function pl_dart_flutter_setsrc (line 55) | void
  function pl_dart_flutter_resetsrc (line 88) | void

FILE: src/recipe/lang/Dart/Pub.c
  function pl_dart_prelude (line 7) | void
  function pl_dart_getsrc (line 40) | void
  function pl_dart_setsrc (line 51) | void
  function pl_dart_resetsrc (line 85) | void

FILE: src/recipe/lang/Go.c
  function pl_go_prelude (line 21) | void
  function pl_go_getsrc (line 71) | void
  function pl_go_setsrc (line 82) | void
  function pl_go_resetsrc (line 99) | void

FILE: src/recipe/lang/Haskell.c
  function pl_haskell_prelude (line 7) | void

FILE: src/recipe/lang/Java.c
  function pl_java_prelude (line 7) | void
  function pl_java_check_cmd (line 51) | void
  function pl_java_is_maven_home_line (line 66) | bool
  function pl_java_getsrc (line 114) | void
  function pl_java_setsrc (line 136) | void
  function pl_java_resetsrc (line 175) | void

FILE: src/recipe/lang/JavaScript/Bun.c
  function pl_js_bun_prelude (line 7) | void
  function pl_js_bun_getsrc (line 34) | void
  function pl_js_bun_setsrc (line 48) | void
  function pl_js_bun_resetsrc (line 77) | void

FILE: src/recipe/lang/JavaScript/JavaScript.c
  function pl_js_check_cmd (line 12) | void
  function pl_js_group_getsrc (line 29) | void
  function pl_js_group_setsrc (line 57) | void
  function pl_js_group_resetsrc (line 97) | void

FILE: src/recipe/lang/JavaScript/Yarn.c
  function pl_js_yarn_prelude (line 7) | void
  function pl_js_yarn_get_yarn_version (line 31) | static double
  function pl_js_yarn_getsrc (line 40) | void
  function pl_js_yarn_setsrc (line 57) | void
  function pl_js_yarn_resetsrc (line 99) | void

FILE: src/recipe/lang/JavaScript/common.h
  function pl_js_group_prelude (line 14) | void
  function pl_js_nodejs_binary_prelude (line 52) | void

FILE: src/recipe/lang/JavaScript/npm.c
  function pl_js_npm_prelude (line 7) | void
  function pl_js_npm_getsrc (line 32) | void
  function pl_js_npm_setsrc (line 42) | void
  function pl_js_npm_resetsrc (line 66) | void

FILE: src/recipe/lang/JavaScript/nvm.c
  function pl_js_nvm_prelude (line 7) | void
  function pl_js_nvm_getsrc (line 34) | void
  function pl_js_nvm_setsrc (line 48) | void
  function pl_js_nvm_resetsrc (line 68) | void

FILE: src/recipe/lang/JavaScript/pnpm.c
  function pl_js_pnpm_prelude (line 7) | void
  function pl_js_pnpm_getsrc (line 32) | void
  function pl_js_pnpm_setsrc (line 43) | void
  function pl_js_pnpm_resetsrc (line 67) | void

FILE: src/recipe/lang/Julia.c
  function pl_julia_prelude (line 7) | void
  function pl_julia_setsrc (line 56) | void

FILE: src/recipe/lang/Lua.c
  function pl_lua_prelude (line 14) | void
  function pl_lua_getsrc (line 42) | void
  function pl_lua_setsrc (line 52) | void

FILE: src/recipe/lang/NuGet.c
  function pl_nuget_prelude (line 7) | void
  function pl_nuget_getsrc (line 35) | void
  function pl_nuget_setsrc (line 45) | void

FILE: src/recipe/lang/OCaml.c
  function pl_ocaml_prelude (line 7) | void
  function pl_ocaml_check_cmd (line 35) | void
  function pl_ocaml_getsrc (line 42) | void
  function pl_ocaml_setsrc (line 53) | void

FILE: src/recipe/lang/PHP.c
  function pl_php_prelude (line 7) | void
  function pl_php_getsrc (line 47) | void
  function pl_php_setsrc (line 57) | void

FILE: src/recipe/lang/Perl.c
  function pl_perl_prelude (line 7) | void
  function pl_perl_check_cmd (line 50) | void
  function pl_perl_getsrc (line 56) | void
  function pl_perl_setsrc (line 71) | void

FILE: src/recipe/lang/Python/PDM.c
  function pl_python_pdm_prelude (line 7) | void
  function pl_python_pdm_getsrc (line 32) | void
  function pl_python_pdm_setsrc (line 45) | void
  function pl_python_pdm_resetsrc (line 68) | void

FILE: src/recipe/lang/Python/Poetry.c
  function pl_python_poetry_prelude (line 7) | void
  function pl_python_poetry_getsrc (line 32) | void
  function pl_python_poetry_setsrc (line 42) | void
  function pl_python_poetry_resetsrc (line 60) | void

FILE: src/recipe/lang/Python/Python.c
  function pl_python_group_getsrc (line 11) | void
  function pl_python_group_setsrc (line 42) | void
  function pl_python_group_resetsrc (line 89) | void

FILE: src/recipe/lang/Python/Rye.c
  function pl_python_rye_prelude (line 9) | void
  function pl_python_rye_getsrc (line 44) | void
  function pl_python_rye_setsrc (line 55) | void
  function pl_python_rye_resetsrc (line 75) | void

FILE: src/recipe/lang/Python/common.h
  function pl_python_group_prelude (line 30) | void
  function pl_python_check_unofficial_pkger (line 81) | void
  function pl_python_get_py_program_name (line 93) | void

FILE: src/recipe/lang/Python/pip.c
  function pl_python_pip_prelude (line 7) | void
  function pl_python_pip_getsrc (line 32) | void
  function pl_python_pip_setsrc (line 63) | void
  function pl_python_pip_resetsrc (line 97) | void

FILE: src/recipe/lang/Python/uv.c
  function pl_python_uv_prelude (line 7) | void
  function pl_python_uv_getsrc (line 86) | void
  function pl_python_uv_setsrc (line 117) | void
  function pl_python_uv_resetsrc (line 194) | void

FILE: src/recipe/lang/R.c
  function pl_r_prelude (line 7) | void
  function pl_r_setsrc (line 66) | void

FILE: src/recipe/lang/Ruby/Ruby.c
  function pl_ruby_prelude (line 14) | void
  function pl_ruby_getsrc (line 51) | void
  function pl_ruby_remove_gem_source (line 58) | bool
  function pl_ruby_setsrc (line 73) | void
  function pl_ruby_resetsrc (line 108) | void

FILE: src/recipe/lang/Rust/Cargo.c
  function pl_rust_cargo_prelude (line 7) | void
  function pl_rust_cargo_note_get_src_mirror (line 74) | void
  function pl_rust_cargo_getsrc (line 81) | void
  function pl_write_rust_config (line 118) | void
  function pl_rust_cargo_setsrc (line 131) | void
  function pl_rust_cargo_resetsrc (line 196) | void

FILE: src/recipe/lang/Rust/rustup.c
  function pl_rust_rustup_prelude (line 10) | void
  function pl_rust_rustup_getsrc (line 50) | void
  function pl_rust_rustup_setsrc (line 60) | void
  function pl_rust_rustup_resetsrc (line 114) | void

FILE: src/recipe/menu.c
  function chsrc_init_menu (line 108) | void

FILE: src/recipe/os/APT/Armbian.c
  function os_armbian_prelude (line 7) | void
  function os_armbian_setsrc (line 59) | void
  function os_armbian_resetsrc (line 79) | void

FILE: src/recipe/os/APT/Debian.c
  function os_debian_prelude (line 7) | void
  function os_debian_getsrc (line 50) | void
  function os_debian_does_old_sourcelist_use_cdrom (line 72) | static bool
  function os_debian_setsrc_for_deb822 (line 84) | void
  function os_debian_setsrc (line 111) | void
  function os_debian_resetsrc (line 169) | void

FILE: src/recipe/os/APT/Kali-Linux.c
  function os_kali_prelude (line 7) | void
  function os_kali_setsrc (line 46) | void
  function os_kali_resetsrc (line 67) | void

FILE: src/recipe/os/APT/Linux-Lite.c
  function os_linuxlite_prelude (line 7) | void
  function os_linuxlite_setsrc (line 45) | void
  function os_linuxlite_resetsrc (line 63) | void

FILE: src/recipe/os/APT/Linux-Mint.c
  function os_linuxmint_prelude (line 7) | void
  function os_linuxmint_setsrc (line 57) | void

FILE: src/recipe/os/APT/ROS.c
  function os_ros_prelude (line 7) | void
  function os_ros_setsrc (line 54) | void

FILE: src/recipe/os/APT/Raspberry-Pi-OS.c
  function os_raspberrypi_prelude (line 9) | void
  function os_raspberrypi_setsrc (line 49) | void
  function os_raspberrypi_resetsrc (line 69) | void

FILE: src/recipe/os/APT/Termux.c
  function os_termux_prelude (line 7) | void
  function os_termux_setsrc (line 57) | void
  function os_termux_resetsrc (line 76) | void

FILE: src/recipe/os/APT/Trisquel.c
  function os_trisquel_prelude (line 9) | void
  function os_trisquel_setsrc (line 50) | void
  function os_trisquel_resetsrc (line 69) | void

FILE: src/recipe/os/APT/Ubuntu.c
  function os_ubuntu_prelude (line 8) | void
  function os_ubuntu_getsrc (line 58) | void
  function os_ubuntu_setsrc_for_deb822 (line 83) | void
  function os_ubuntu_setsrc (line 111) | void
  function os_ubuntu_resetsrc (line 156) | void

FILE: src/recipe/os/APT/common.h
  function ensure_debian_or_ubuntu_old_sourcelist (line 56) | bool

FILE: src/recipe/os/APT/deepin.c
  function os_deepin_prelude (line 7) | void
  function os_deepin_setsrc (line 52) | void
  function os_deepin_resetsrc (line 73) | void

FILE: src/recipe/os/APT/openKylin.c
  function os_openkylin_prelude (line 10) | void
  function os_openkylin_setsrc (line 43) | void
  function os_openkylin_resetsrc (line 61) | void

FILE: src/recipe/os/Alpine-Linux.c
  function os_alpine_prelude (line 7) | void
  function os_alpine_getsrc (line 43) | void
  function os_alpine_setsrc (line 53) | void

FILE: src/recipe/os/BSD/FreeBSD.c
  function os_freebsd_prelude (line 7) | void

FILE: src/recipe/os/BSD/NetBSD.c
  function os_netbsd_prelude (line 7) | void
  function os_netbsd_setsrc (line 56) | void

FILE: src/recipe/os/BSD/OpenBSD.c
  function os_openbsd_prelude (line 7) | void
  function os_openbsd_setsrc (line 55) | void

FILE: src/recipe/os/Gentoo-Linux.c
  function os_gentoo_prelude (line 7) | void

FILE: src/recipe/os/OpenWrt.c
  function os_openwrt_prelude (line 7) | void
  function os_openwrt_getsrc (line 45) | void
  function os_openwrt_setsrc (line 56) | void
  function os_openwrt_resetsrc (line 75) | void

FILE: src/recipe/os/Solus.c
  function os_solus_prelude (line 7) | void

FILE: src/recipe/os/Void-Linux.c
  function os_voidlinux_prelude (line 7) | void
  function os_voidlinux_getsrc (line 38) | void
  function os_voidlinux_setsrc (line 48) | void
  function os_voidlinux_resetsrc (line 76) | void

FILE: src/recipe/os/YUM/AlmaLinux.c
  function os_almalinux_prelude (line 7) | void
  function os_almalinux_setsrc (line 44) | void

FILE: src/recipe/os/YUM/Anolis-OS.c
  function os_anolis_prelude (line 7) | void
  function os_anolis_setsrc (line 37) | void

FILE: src/recipe/os/YUM/Fedora-Linux.c
  function os_fedora_prelude (line 7) | void
  function os_fedora_resetsrc (line 91) | void

FILE: src/recipe/os/YUM/Rocky-Linux.c
  function os_rockylinux_prelude (line 7) | void
  function os_rockylinux_resetsrc (line 85) | void

FILE: src/recipe/os/YUM/openEuler.c
  function os_openeuler_prelude (line 7) | void
  function os_openeuler_getsrc (line 48) | void
  function os_openeuler_setsrc (line 58) | void
  function os_openeuler_resetsrc (line 88) | void

FILE: src/recipe/os/openSUSE.c
  function os_opensuse_prelude (line 7) | void

FILE: src/recipe/os/pacman/Arch-Linux.c
  function os_arch_prelude (line 10) | void
  function os_arch_setsrc (line 65) | void
  function os_archlinuxcn_prelude (line 113) | void
  function os_archlinuxcn_setsrc (line 161) | void

FILE: src/recipe/os/pacman/MSYS2.c
  function os_msys2_prelude (line 7) | void

FILE: src/recipe/os/pacman/Manjaro-Linux.c
  function os_manjaro_prelude (line 7) | void
  function os_manjaro_setsrc (line 32) | void

FILE: src/recipe/recipe-template.c
  function _resetsrc (line 136) | void

FILE: src/recipe/ware/Anaconda/Anaconda.c
  function wr_anaconda_prelude (line 9) | void
  function wr_anaconda_setsrc (line 56) | void

FILE: src/recipe/ware/CocoaPods.c
  function wr_cocoapods_prelude (line 7) | void

FILE: src/recipe/ware/Docker/Docker.c
  function wr_docker_prelude (line 24) | void
  function wr_docker_setsrc (line 73) | void

FILE: src/recipe/ware/Emacs.c
  function wr_emacs_prelude (line 14) | void

FILE: src/recipe/ware/Flatpak.c
  function wr_flatpak_prelude (line 7) | void
  function wr_flatpak_getsrc (line 56) | void
  function wr_flatpak_setsrc (line 67) | void
  function wr_flatpak_resetsrc (line 92) | void

FILE: src/recipe/ware/Guix.c
  function wr_guix_prelude (line 7) | void
  function wr_guix_setsrc (line 41) | void

FILE: src/recipe/ware/Homebrew/Homebrew.c
  function wr_homebrew_prelude (line 9) | void
  function wr_homebrew_setsrc (line 57) | void

FILE: src/recipe/ware/Nix.c
  function wr_nix_is_multi_user_installation_mode (line 12) | bool
  function wr_nix_prelude (line 25) | void
  function wr_nix_setsrc (line 79) | void

FILE: src/recipe/ware/TeX-Live.c
  function wr_tex_prelude (line 9) | void
  function wr_tex_getsrc (line 64) | void
  function wr_tex_setsrc (line 83) | void

FILE: src/recipe/ware/WinGet.c
  function wr_winget_prelude (line 7) | void
  function wr_winget_setsrc (line 49) | void
  function wr_winget_resetsrc (line 65) | void

FILE: test/fw.c
  function main (line 16) | int

FILE: test/xy.c
  function callback_print_str_for_seq (line 15) | void
  function callback_print_str_for_map (line 21) | void
  function main (line 28) | int
Condensed preview — 178 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (631K chars).
[
  {
    "path": ".editorconfig",
    "chars": 1044,
    "preview": "# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# ---------"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 99,
    "preview": "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",
    "chars": 1997,
    "preview": "name: 🐞 Bug 报告\ndescription: 有 Bug 了吗?\ntitle: \"详细报告BUG是chsrc用户的一大美德\"\n# labels: [ ]\ntype: Bug\nbody:\n  - type: markdown\n   "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/02-Request_Recipe.yml",
    "chars": 697,
    "preview": "name: 🫡 我想要对 target 换源!\ndescription: 想要对尚未支持的 target 进行换源?\ntitle: \"提前找好方案怎么换源是chsrc用户的一大美德\"\n# labels: [ ]\ntype: Request\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/03-Share.yml",
    "chars": 466,
    "preview": "name: 🎉 我找到了新的镜像站或源!\ndescription: 为大家分享新的镜像站或可用源!\ntitle: \"分享是chsrc用户的一大美德\"\n# labels: [ ]\ntype: Contribute\nbody:\n  - type"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/04-Deprecate.yml",
    "chars": 408,
    "preview": "name: ⛓️‍💥 镜像源已失效\ndescription: 该镜像站已关停/该源已不再被支持\ntitle: \"报告镜像源情况是chsrc用户的一大美德\"\n# labels: [ ]\ntype: Deprecate\nbody:\n  - ty"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 183,
    "preview": "blank_issues_enabled: true\ncontact_links:\n  - name: ❤️ 赞赏支持 chsrc\n    url: https://afdian.com/a/ccmywish\n    # about 不支持"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Add_Feature.md",
    "chars": 100,
    "preview": "## 新功能描述\n\n请描述该新功能,为什么要增加这个功能,以及具体的用例\n\n---\n\n## 方案\n\n请介绍你新增加该功能的方案\n\n---\n\n## 实现\n\n请介绍你的实现(若实现相当直接则不需要描述)\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Clean.md",
    "chars": 171,
    "preview": "## 描述\n\n注意: 小改动请使用该PR模板。而中等、大型规模的变化,或者引起巨大联动变化的改动,需要使用 `Refactor` PR模板。\n\n请介绍你进行了什么清理,如某部分代码,如某部分文档\n\n---\n\n## 方案\n\n请介绍你进行清理的"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Enhance.md",
    "chars": 99,
    "preview": "## 改进描述\n\n请描述要改进的具体内容,为什么要增强/改善它,以及具体的用例\n\n---\n\n## 方案\n\n请介绍你的改进方案\n\n---\n\n## 实现\n\n请介绍你的实现(若实现相当直接则不需要描述)\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Fix_Bug.md",
    "chars": 125,
    "preview": "## 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请介绍你的实现(若实现相当直接则不需"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Implement.md",
    "chars": 283,
    "preview": "## 问题描述\n\n(此内容必填)\n\n1. 简要说明此 PR 修复的具体问题或改进的功能背景\n2. 列出与此 PR 相关的 issue 或任务,若没有填 `N/A`\n\n<br>\n\n\n\n## 方案\n\n(此内容必填)\n\n详细描述针对该问题或功能改"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Refactor.md",
    "chars": 149,
    "preview": "## 背景\n\n注意: 中等、大型规模的变化,或者引起巨大联动变化的改动,才需要使用该模板。中小改动请使用 `Clean` PR模板。\n\n请介绍该重构的背景,可以带来哪些优势?\n\n---\n\n## 方案\n\n请介绍你进行重构的方案\n\n---\n\n#"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/Relate_Mirror_Source.md",
    "chars": 120,
    "preview": "## 可用性确认\n\n1. 请你本人确认这些源真的可用或已经失效,不要等待其它用户帮你测试\n\n2. 请确保修改后代码依然可以编译及运行\n\n3. 请在你修改的各个文件的标头部分增加你自己的贡献信息,名字栏需要为中文拼音、或者英文名、或者账号名\n"
  },
  {
    "path": ".github/READIT.md",
    "chars": 671,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": ".github/copilot-instructions.md",
    "chars": 677,
    "preview": "# chsrc Project Rules for AI Assistants\n\n## 项目概述\n\n这是 chsrc 项目,一个用 C 语言编写的跨平台命令行换源工具,帮助用户在不同的镜像之间切换,适用于编程语言、操作系统、其他软件。它的最"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 114,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: github-actions\n    directory: \"/\"\n    schedule:\n      interval: weekly\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 118,
    "preview": "## 问题描述\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",
    "chars": 1859,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : PR-notify.yml\n# File Authors  : 曾奥然 "
  },
  {
    "path": ".github/workflows/PR-test.yml",
    "chars": 1665,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : PR-test.yml\n# File Authors  : 曾奥然 <c"
  },
  {
    "path": ".github/workflows/build-on-Linux-AArch64.yml",
    "chars": 1335,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : build-on-Linux-AArch64.yml\n# File Au"
  },
  {
    "path": ".github/workflows/build-on-Linux-ARMv7.yml",
    "chars": 1321,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : build-on-Linux-ARMv7.yml\n# File Auth"
  },
  {
    "path": ".github/workflows/build-on-Linux-riscv64.yml",
    "chars": 1335,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : build-on-Linux-riscv64.yml\n# File Au"
  },
  {
    "path": ".github/workflows/build-on-Linux-x64.yml",
    "chars": 943,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : build-on-Linux-x64.yml\n# File Author"
  },
  {
    "path": ".github/workflows/build-on-Windows.yml",
    "chars": 1930,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : build-on-Windows.yml\n# File Authors "
  },
  {
    "path": ".github/workflows/build-on-macOS.yml",
    "chars": 1757,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : build-on-macOS.yml\n# File Authors  :"
  },
  {
    "path": ".github/workflows/pkg-deb.yml",
    "chars": 4635,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : pkg-deb.yml\n# File Authors  : sanchu"
  },
  {
    "path": ".github/workflows/pub-AUR-chsrc-and-chsrc-bin.yml",
    "chars": 2622,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : pub-AUR-chsrc-and-chsrc-bin.yml\n# Fi"
  },
  {
    "path": ".github/workflows/pub-AUR-chsrc-git.yml",
    "chars": 1223,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : pub-AUR-chsrc-git.yml\n# File Authors"
  },
  {
    "path": ".github/workflows/pub-WinGet.yml",
    "chars": 691,
    "preview": "# ---------------------------------------------------------------\n# Workflow File : pub-WinGet.yml\n# File Authors  :   Y"
  },
  {
    "path": ".gitignore",
    "chars": 1387,
    "preview": "##############################\n#          VS Code\n##############################\n.vscode/*\n!.vscode/extensions.json\n!.vs"
  },
  {
    "path": ".vscode/README.md",
    "chars": 609,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": ".vscode/c_cpp_properties.json",
    "chars": 637,
    "preview": "{\n    \"configurations\": [\n        {\n            \"name\": \"Win32\",\n            \"includePath\": [\n                \"${workspa"
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 286,
    "preview": "{\n    \"recommendations\": [\n        \"ms-vscode.cpptools\",\n        \"ms-vscode.cpptools-extension-pack\",\n        \"editorcon"
  },
  {
    "path": ".vscode/launch.json",
    "chars": 2095,
    "preview": "{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Debug chsrc\",\n            \"type\": \"cppd"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 646,
    "preview": "{\n    \"editor.fontLigatures\": false,\n\n    \"C_Cpp.autoAddFileAssociations\": false,\n    \"C_Cpp.intelliSenseEngine\": \"Tag P"
  },
  {
    "path": ".vscode/tasks.json",
    "chars": 4911,
    "preview": "{\n    \"tasks\": [\n        {\n            \"type\": \"shell\",\n            \"label\": \"构建 chsrc\",\n            \"command\": \"just\",\n"
  },
  {
    "path": "COPYING",
    "chars": 35149,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "LICENSE-MIT.txt",
    "chars": 1124,
    "preview": "MIT License\n\nCopyright (c) 2023-2026 曾奥然 (Aoran Zeng), 郭恒 (Heng Guo)\n\nPermission is hereby granted, free of charge, to a"
  },
  {
    "path": "Makefile",
    "chars": 5511,
    "preview": "#!/usr/bin/make -f\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-o"
  },
  {
    "path": "README.md",
    "chars": 13706,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "bootstrap/README.md",
    "chars": 1993,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "bootstrap/Termux.bash",
    "chars": 1759,
    "preview": "#!/usr/bin/env bash\n# ---------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0"
  },
  {
    "path": "doc/01-开发与构建.md",
    "chars": 2277,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "doc/02-提交与贡献.md",
    "chars": 1295,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "doc/03-为什么拒绝使用代码格式化工具.md",
    "chars": 2603,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "doc/10-如何编写recipe.md",
    "chars": 3602,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "doc/11-如何设置换源链接与测速链接.md",
    "chars": 2699,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "doc/50-协作者与维护者.md",
    "chars": 1049,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "doc/README.md",
    "chars": 1059,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "doc/chsrc.1",
    "chars": 2525,
    "preview": ".\\\" --------------------------------------------------------------\n.\\\" SPDX-License-Identifier: GFDL-1.3-or-later\n.\\\" --"
  },
  {
    "path": "doc/chsrc.texi",
    "chars": 2811,
    "preview": "@c --------------------------------------------------------------\n@c SPDX-License-Identifier: GFDL-1.3-or-later\n@c -----"
  },
  {
    "path": "include/.keep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "justfile",
    "chars": 4637,
    "preview": "#!/usr/bin/env just --justfile\n# --------------------------------------------------------------\n# SPDX-License-Identifie"
  },
  {
    "path": "lefthook.yml",
    "chars": 1085,
    "preview": "# ---------------------------------------------------------------\n# Lefthook File : lefthook.yml\n# File Authors  : 曾奥然 <"
  },
  {
    "path": "lib/xy.h",
    "chars": 36343,
    "preview": "/** ------------------------------------------------------------\n * Copyright © 2023-2026 曾奥然, 郭恒\n * SPDX-License-Identi"
  },
  {
    "path": "pkg/AUR/README.md",
    "chars": 1082,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "pkg/README.md",
    "chars": 831,
    "preview": "# Packages\n\n## 分发情况\n\n- [x] `Homebrew`\n- [x] `Scoop`\n- [x] `WinGet`\n- [x] `AUR`\n- [ ] `Flatpak`\n- [ ] `snap`\n- [ ] ...\n\n<"
  },
  {
    "path": "pkg/deb/BUILD.md",
    "chars": 1739,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "pkg/deb/CI.md",
    "chars": 1251,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "pkg/deb/Makefile",
    "chars": 1205,
    "preview": "#!/usr/bin/make -f\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-o"
  },
  {
    "path": "pkg/deb/README.md",
    "chars": 1351,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "pkg/deb/deb-installation-test.sh",
    "chars": 1507,
    "preview": "#!/bin/bash\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later"
  },
  {
    "path": "pkg/deb/debian/changelog",
    "chars": 370,
    "preview": "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\nc"
  },
  {
    "path": "pkg/deb/debian/control",
    "chars": 703,
    "preview": "Source: chsrc\nSection: utils\nPriority: optional\nMaintainer: sanchuanhehe <wyihe5520@gmail.com>\nBuild-Depends: debhelper-"
  },
  {
    "path": "pkg/deb/debian/copyright",
    "chars": 2661,
    "preview": "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nUpstream-Name: chsrc\nUpstream-Contact: 曾奥然 <c"
  },
  {
    "path": "pkg/deb/debian/postinst",
    "chars": 1054,
    "preview": "#!/bin/sh\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n#"
  },
  {
    "path": "pkg/deb/debian/prerm",
    "chars": 743,
    "preview": "#!/bin/sh\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n#"
  },
  {
    "path": "pkg/deb/debian/rules",
    "chars": 1200,
    "preview": "#!/usr/bin/make -f\n# --------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-o"
  },
  {
    "path": "src/chsrc-main.c",
    "chars": 32454,
    "preview": "/** ------------------------------------------------------------\n * Copyright © 2023-2026 曾奥然, 郭恒\n * SPDX-License-Identi"
  },
  {
    "path": "src/framework/chef.c",
    "chars": 11381,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/framework/core.c",
    "chars": 50499,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/framework/helper.c",
    "chars": 1082,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/framework/mirror.c",
    "chars": 8657,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/framework/struct.h",
    "chars": 6752,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/framework/version.h",
    "chars": 732,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/rawstr4c.h",
    "chars": 21490,
    "preview": "#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\\"
  },
  {
    "path": "src/rawstr4c.md",
    "chars": 5546,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------"
  },
  {
    "path": "src/recipe/lang/Clojure.c",
    "chars": 2116,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Dart/Flutter.c",
    "chars": 2597,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Dart/Pub.c",
    "chars": 2415,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Dart/common.h",
    "chars": 724,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Go.c",
    "chars": 2576,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Haskell.c",
    "chars": 2261,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Java.c",
    "chars": 5603,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/JavaScript/Bun.c",
    "chars": 1907,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/JavaScript/JavaScript.c",
    "chars": 2328,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/JavaScript/Yarn.c",
    "chars": 2793,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/JavaScript/common.h",
    "chars": 3063,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/JavaScript/npm.c",
    "chars": 1720,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/JavaScript/nvm.c",
    "chars": 1919,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/JavaScript/pnpm.c",
    "chars": 1771,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Julia.c",
    "chars": 1790,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Lua.c",
    "chars": 1932,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/NuGet.c",
    "chars": 1371,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/OCaml.c",
    "chars": 1777,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/PHP.c",
    "chars": 1951,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Perl.c",
    "chars": 3316,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Python/PDM.c",
    "chars": 1836,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Python/Poetry.c",
    "chars": 1694,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Python/Python.c",
    "chars": 2003,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Python/Rye.c",
    "chars": 2100,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Python/common.h",
    "chars": 5128,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Python/pip.c",
    "chars": 2732,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Python/rawstr4c.h",
    "chars": 3079,
    "preview": "#pragma once\n\n/**\n * Generated by rawstr4c v1.1.0-2025/09/27\n */\n\nchar RAWSTR_pl_python_uv_config_source_content[] = \"\\x"
  },
  {
    "path": "src/recipe/lang/Python/rawstr4c.md",
    "chars": 1832,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------"
  },
  {
    "path": "src/recipe/lang/Python/uv.c",
    "chars": 5429,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/R.c",
    "chars": 2620,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Ruby/README.md",
    "chars": 230,
    "preview": "# Ruby 换源问题\n\nhttps://github.com/ustclug/discussions/issues/438\n\n\n- 清华、北京外国语: 不可用,原因是: 实现不足 https://github.com/tuna/issue"
  },
  {
    "path": "src/recipe/lang/Ruby/Ruby.c",
    "chars": 3400,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Rust/Cargo.c",
    "chars": 7022,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Rust/common.h",
    "chars": 625,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/Rust/rustup.c",
    "chars": 3585,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/lang/rawstr4c.h",
    "chars": 6891,
    "preview": "#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"
  },
  {
    "path": "src/recipe/lang/rawstr4c.md",
    "chars": 2754,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------"
  },
  {
    "path": "src/recipe/menu.c",
    "chars": 5360,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/Armbian.c",
    "chars": 2469,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/Debian.c",
    "chars": 4955,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/Kali-Linux.c",
    "chars": 2007,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/Linux-Lite.c",
    "chars": 1703,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/Linux-Mint.c",
    "chars": 3193,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/ROS.c",
    "chars": 2341,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/Raspberry-Pi-OS.c",
    "chars": 2220,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/Termux.c",
    "chars": 2596,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/Trisquel.c",
    "chars": 1989,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/Ubuntu.c",
    "chars": 4528,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/common.h",
    "chars": 3886,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/deepin.c",
    "chars": 2196,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/openKylin.c",
    "chars": 1710,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/APT/rawstr4c.h",
    "chars": 4347,
    "preview": "#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[] = \"\\"
  },
  {
    "path": "src/recipe/os/APT/rawstr4c.md",
    "chars": 1931,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------"
  },
  {
    "path": "src/recipe/os/Alpine-Linux.c",
    "chars": 2136,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/BSD/FreeBSD.c",
    "chars": 4783,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/BSD/NetBSD.c",
    "chars": 2621,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/BSD/OpenBSD.c",
    "chars": 2322,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/Gentoo-Linux.c",
    "chars": 1729,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/OpenWrt.c",
    "chars": 2483,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/Solus.c",
    "chars": 1486,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/Void-Linux.c",
    "chars": 2099,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/YUM/AlmaLinux.c",
    "chars": 1999,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/YUM/Anolis-OS.c",
    "chars": 1470,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/YUM/Fedora-Linux.c",
    "chars": 2896,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/YUM/Rocky-Linux.c",
    "chars": 2963,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/YUM/common.h",
    "chars": 589,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/YUM/openEuler.c",
    "chars": 2653,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/openSUSE.c",
    "chars": 2439,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/pacman/Arch-Linux.c",
    "chars": 6059,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/pacman/MSYS2.c",
    "chars": 2108,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/pacman/Manjaro-Linux.c",
    "chars": 978,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/os/rawstr4c.h",
    "chars": 2920,
    "preview": "#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"
  },
  {
    "path": "src/recipe/os/rawstr4c.md",
    "chars": 1335,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------"
  },
  {
    "path": "src/recipe/recipe-template.c",
    "chars": 3808,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/ware/Anaconda/Anaconda.c",
    "chars": 2854,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/ware/Anaconda/rawstr4c.h",
    "chars": 1003,
    "preview": "#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\\"
  },
  {
    "path": "src/recipe/ware/Anaconda/rawstr4c.md",
    "chars": 844,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------"
  },
  {
    "path": "src/recipe/ware/CocoaPods.c",
    "chars": 1927,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/ware/Docker/Docker.c",
    "chars": 4476,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/ware/Docker/README.md",
    "chars": 87,
    "preview": "# Docker\n\n- USTC 与 SJTUG 于 2024-06-06 停止支持 DockerHub\n- NJU 于 2024-06-07 停止支持 DockerHub\n"
  },
  {
    "path": "src/recipe/ware/Docker/rawstr4c.h",
    "chars": 1058,
    "preview": "#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"
  },
  {
    "path": "src/recipe/ware/Docker/rawstr4c.md",
    "chars": 1203,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------"
  },
  {
    "path": "src/recipe/ware/Emacs.c",
    "chars": 2173,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/ware/Flatpak.c",
    "chars": 3134,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/ware/Guix.c",
    "chars": 1688,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/ware/Homebrew/Homebrew.c",
    "chars": 2668,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/ware/Homebrew/rawstr4c.h",
    "chars": 1144,
    "preview": "#pragma once\n\n/**\n * Generated by rawstr4c v1.0.0-2025/08/09\n */\n\nchar RAWSTR_wr_homebrew_read_config_cmd[] = \"echo HOME"
  },
  {
    "path": "src/recipe/ware/Homebrew/rawstr4c.md",
    "chars": 2105,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GPL-3.0-or-later\n ! -------"
  },
  {
    "path": "src/recipe/ware/Nix.c",
    "chars": 3340,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/ware/TeX-Live.c",
    "chars": 3815,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/recipe/ware/WinGet.c",
    "chars": 2200,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "src/resource/chsrc.rc",
    "chars": 1535,
    "preview": "// chsrc.rc - Windows Resource Script\n// SPDX-License-Identifier: GPL-3.0-or-later\n\n#include <windows.h>\n#include \"../fr"
  },
  {
    "path": "test/cli.pl",
    "chars": 4116,
    "preview": "#!/usr/bin/env perl\n# ---------------------------------------------------------------\n# Test File     : cli.pl\n# Test Au"
  },
  {
    "path": "test/fw.c",
    "chars": 3069,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: GPL-3.0-or-later\n * -------"
  },
  {
    "path": "test/xy.c",
    "chars": 5836,
    "preview": "/** ------------------------------------------------------------\n * SPDX-License-Identifier: MIT\n * --------------------"
  },
  {
    "path": "tool/README.md",
    "chars": 832,
    "preview": "<!-- -----------------------------------------------------------\n ! SPDX-License-Identifier: GFDL-1.3-or-later\n ! ------"
  },
  {
    "path": "tool/download-pre-on-GitHub.ps1",
    "chars": 1570,
    "preview": "# ---------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# --------"
  },
  {
    "path": "tool/git-ignore-vscode-settings.ps1",
    "chars": 632,
    "preview": "# ---------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# --------"
  },
  {
    "path": "tool/installer.ps1",
    "chars": 6361,
    "preview": "# ---------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0-or-later\n# --------"
  },
  {
    "path": "tool/installer.sh",
    "chars": 10191,
    "preview": "#!/usr/bin/env bash\n# ---------------------------------------------------------------\n# SPDX-License-Identifier: GPL-3.0"
  }
]

About this extraction

This page contains the full source code of the RubyMetric/chsrc GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 178 files (569.3 KB), approximately 192.5k tokens, and a symbol index with 391 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!