Move to include

This commit is contained in:
Aoran Zeng
2024-05-24 16:45:18 +08:00
parent 44d9acd6b0
commit d1da065906
4 changed files with 17 additions and 15 deletions

373
include/chsrc.h Normal file
View File

@@ -0,0 +1,373 @@
/** ------------------------------------------------------------
* File : chsrc.h
* License : GPLv3
* Authors : Aoran Zeng <ccmywish@qq.com>
* Created on : <2023-08-29>
* Last modified : <2023-10-05>
*
* chsrc:
*
* chsrc.c 头文件
* ------------------------------------------------------------*/
#include "xy.h"
#include "sources.h"
#define App_Prefix "chsrc: "
#define chsrc_success(str) xy_success(xy_2strjoin(App_Prefix, (str)))
#define chsrc_info(str) xy_info(xy_2strjoin(App_Prefix, (str)))
#define chsrc_warn(str) xy_warn(xy_2strjoin(App_Prefix, (str)))
#define chsrc_error(str) xy_error(xy_2strjoin(App_Prefix, (str)))
/**
* 检测二进制程序是否存在
*
* @param check_cmd 检测 `progname` 是否存在的一段命令,一般来说,填 `progname` 本身即可,
* 但是某些情况下,需要使用其他命令绕过一些特殊情况,比如 python 这个命令在Windows上
* 会自动打开 Microsoft Store需避免
*
* @param progname 要检测的二进制程序名
*/
bool
query_program_exist (char* check_cmd, char* progname)
{
char* which = check_cmd;
int ret = system(which);
// char buf[32] = {0}; sprintf(buf, "错误码: %d", ret);
if (0!=ret) {
// xy_warn (xy_strjoin(4, "× 命令 ", progname, " 不存在,", buf));
xy_warn (xy_strjoin(3, "× 命令 ", progname, " 不存在"));
return false;
} else {
xy_success (xy_strjoin(3, "√ 命令 ", progname, " 存在"));
return true;
}
}
/**
* 用于 _setsrc 函数检测用户输入的镜像站code是否存在于该target可用源中
*
* @param target 目标名
* @param input 如果用户输入 default 或者 def则选择第一个源
*/
#define find_mirror(s, input) query_mirror_exist(s##_sources, s##_sources_n, (char*)#s+3, input)
int
query_mirror_exist (SourceInfo* sources, size_t size, char* target, char* input)
{
if (0==size) {
xy_error(xy_strjoin(3, "chsrc: 当前 ", target, " 无任何可用源,请联系维护者"));
exit(1);
}
if (1==size) {
xy_success(xy_strjoin(5, "chsrc: ", sources[0].mirror->name, "", target, " 目前唯一可用镜像站,感谢他们的慷慨支持"));
}
if (xy_streql("default", input) || xy_streql("def", input)) {
xy_info ("chsrc: 默认使用维护团队测速第一的源");
return 0;
}
int idx = 0;
SourceInfo source = sources[0];
bool exist = false;
for (int i=0; i<size; i++)
{
source = sources[i];
if (xy_streql(source.mirror->code, input)) {
idx = i;
exist = true;
break;
}
}
if (!exist) {
xy_error (xy_strjoin(3, "chsrc: 镜像站 ", input, " 不存在"));
xy_error (xy_2strjoin("chsrc: 查看可使用源,请使用 chsrc list ", target));
exit(1);
}
return idx;
}
/**
* 该函数来自 oh-my-mirrorz.py由 @ccmywish 翻译为C语言但功劳和版权属于原作者
*/
char*
to_human_readable_speed (double speed)
{
char* scale[] = {"Byte/s", "KByte/s", "MByte/s", "GByte/s", "TByte/s"};
int i = 0;
while (speed > 1024.0)
{
i += 1;
speed /= 1024.0;
}
char* buf = xy_malloc0(64);
sprintf(buf, "%.2f %s", speed, scale[i]);
char* new = NULL;
if (i <= 1 ) new = xy_str_to_red(buf);
else
{
if (i == 2 && speed < 2.00) new = xy_str_to_yellow(buf);
else new = xy_str_to_green(buf);
}
return new;
}
/**
* 测速代码参考自 https://github.com/mirrorz-org/oh-my-mirrorz/blob/master/oh-my-mirrorz.py
* 功劳和版权属于原作者,由 @ccmywish 修改为C语言并做了额外调整
*
* @return 返回测得的速度,若出错,返回-1
*/
double
test_speed_url (const char* url)
{
char* time_sec = "6";
/* 现在我们切换至跳转后的链接来测速,不再使用下述判断
if (xy_str_start_with(url, "https://registry.npmmirror"))
{
// 这里 npmmirror 跳转非常慢需要1~3秒所以我们给它留够至少8秒测速时间否则非常不准
time_sec = "10";
}
*/
// 我们用 —L因为Ruby China源会跳转到其他地方
// npmmirror 也会跳转
char* curl_cmd = xy_strjoin(6, "curl -qsL -o ", xy_os_devnull,
" -w \"%{http_code} %{speed_download}\" -m", time_sec ,
" -A chsrc/" Chsrc_Version " ", url);
// xy_info (xy_2strjoin("chsrc: 测速 ", url));
char* buf = xy_getcmd (curl_cmd, 0, NULL);
// 如果尾部有换行,删除
buf = xy_str_strip (buf);
// 分隔两部分数据
char* split = strchr(buf, ' ');
if (split) *split = '\0';
// puts(buf); puts(split+1);
int http_code = atoi(buf);
double speed = atof(split+1);
char* speedstr = to_human_readable_speed(speed);
if (200!=http_code) {
char* httpcodestr = xy_str_to_yellow (xy_2strjoin("HTTP码 ", buf));
puts (xy_strjoin (3, speedstr, " | ", httpcodestr));
} else {
puts (speedstr);
}
return speed;
}
int
get_max_ele_idx_in_dbl_ary (double* array, int size)
{
double maxval = array[0];
int maxidx = 0;
for (int i=1; i<size; i++) {
if (array[i]>maxval) {
maxval = array[i];
maxidx = i;
}
}
return maxidx;
}
/**
* 自动测速选择镜像站和源
*/
#define auto_select(s) auto_select_(s##_sources, s##_sources_n, (char*)#s+3)
int
auto_select_ (SourceInfo* sources, size_t size, const char* target)
{
if (0==size) {
xy_error(xy_strjoin(3, "chsrc: 当前 ", target, " 无任何可用源,请联系维护者"));
exit(1);
}
bool onlyone = false;
if (1==size) onlyone = true;
double speeds[size];
double speed = 0.0;
for (int i=0;i<size;i++)
{
SourceInfo src = sources[i];
const char* url = src.mirror->__bigfile_url;
if (NULL==url) {
chsrc_warn ( xy_strjoin(3, "开发者未提供 ", src.mirror->code, " 镜像站测速链接,跳过该站点"));
speed = 0;
} else {
printf ("%s",xy_strjoin(3, "chsrc: 测速 ", src.mirror->site , " ... "));
fflush(stdout);
speed = test_speed_url (url);
}
speeds[i] = speed;
}
int fastidx = get_max_ele_idx_in_dbl_ary (speeds, size);
if (onlyone)
xy_success(xy_strjoin(5, "chsrc: ", sources[fastidx].mirror->name, "", target, " 目前唯一可用镜像站,感谢他们的慷慨支持"));
else
xy_success (xy_2strjoin("chsrc: 最快镜像站: ", sources[fastidx].mirror->name));
return fastidx;
}
#define use_specific_mirror_or_auto_select(input, s) \
(NULL!=(input)) ? find_mirror(s, input) : auto_select(s)
/**
* 用于 _setsrc 函数
*/
void
chsrc_say_selection (SourceInfo* source)
{
xy_info (xy_strjoin(5, "chsrc: 选中镜像站: ", source->mirror->abbr, " (", source->mirror->code, ")"));
}
void
chsrc_say_thanks (SourceInfo* source)
{
xy_success(xy_2strjoin("chsrc: 感谢镜像提供方: ", source->mirror->name));
}
void
chsrc_ensure_root ()
{
char* euid = getenv("$EUID");
if (NULL==euid) {
char* buf = xy_getcmd("id -u", 0, NULL);
if (0!=atoi(buf)) goto not_root;
else return;
} else {
if (0!=atoi(euid)) goto not_root;
else return;
}
not_root:
xy_error("chsrc: 请在命令前使用 sudo 来保证必要的权限");
exit(1);
}
static void
chsrc_run (const char* cmd)
{
xy_info (xy_2strjoin ("chsrc: 运行 ", cmd));
system(cmd);
}
static void
chsrc_check_file (const char* path)
{
char* cmd = NULL;
path = xy_uniform_path (path);
if(xy_on_windows) {
cmd = xy_2strjoin ("type ", path);
} else {
cmd = xy_2strjoin ("cat ", path);
}
chsrc_run (cmd);
}
static void
chsrc_ensure_dir (const char* dir)
{
dir = xy_uniform_path (dir);
char* mkdir_cmd = NULL;
if (xy_on_windows) {
mkdir_cmd = "md ";
} else {
mkdir_cmd = "mkdir -p ";
}
char* cmd = xy_2strjoin (mkdir_cmd, dir);
cmd = xy_str_to_quietcmd (cmd);
chsrc_run (cmd);
}
static void
chsrc_append_to_file (const char* str, const char* file)
{
file = xy_uniform_path (file);
char* dir = xy_parent_dir (file);
chsrc_ensure_dir (dir);
char* cmd = NULL;
if (xy_on_windows) {
cmd = xy_strjoin (4, "echo ", str, " >> ", file);
} else {
cmd = xy_strjoin (4, "echo '", str, "' >> ", file);
}
chsrc_run(cmd);
}
static void
chsrc_overwrite_file (const char* str, const char* file)
{
file = xy_uniform_path (file);
char* dir = xy_parent_dir (file);
chsrc_ensure_dir (dir);
char* cmd = NULL;
if (xy_on_windows) {
cmd = xy_strjoin (4, "echo ", str, " > ", file);
} else {
cmd = xy_strjoin (4, "echo '", str, "' > ", file);
}
chsrc_run(cmd);
}
static void
chsrc_backup (const char* path)
{
char* cmd = NULL;
if (xy_on_bsd)
{
// 似乎BSD的cp并没有 --backup='t' 选项
cmd = xy_strjoin(5, "cp -f ", path, " ", path, ".bak");
}
else if (xy_on_windows) {
// /Y 表示覆盖
cmd = xy_strjoin(5, "copy /Y ", path, " ", path, ".bak" );
}
else {
cmd = xy_strjoin(5, "cp ", path, " ", path, ".bak --backup='t'");
}
chsrc_run (cmd);
chsrc_info ( xy_strjoin (3, "备份文件名 ", path, ".bak"));
}
/* Target Info */
typedef struct {
void (*setfn)(char* option);
void (*getfn)(char* option);
SourceInfo* sources;
size_t sources_n;
} TargetInfo;
#define def_target(t) TargetInfo t##_target = {t##_setsrc, t##_getsrc, t##_sources, t##_sources_n}

840
include/sources.h Normal file
View File

@@ -0,0 +1,840 @@
/** ------------------------------------------------------------
* File : sources.h
* License : GPLv3
* Authors : Aoran Zeng <ccmywish@qq.com>
* Created on : <2023-08-29>
* Last modified : <2024-04-18>
*
* sources:
*
* 镜像站与源信息
* ------------------------------------------------------------*/
typedef struct {
const char* code; // 用于用户指定镜像站
const char* abbr;
const char* name;
const char* site;
const char* __bigfile_url; // 用于对该镜像站测速
} MirrorInfo;
// #define Big_File_ubuntu "/indices/md5sums.gz" 这个是错的
#define Big_File_ctan "/systems/texlive/Images/texlive.iso" // 4.8GB
#define Big_File_debian "/ls-lR.gz" // 13.9 MB
#define Big_File_archlinux "/iso/latest/archlinux-x86_64.iso" // 800MB 左右
#define Big_File_deepin "/20.9/deepin-desktop-community-20.9-amd64.iso" // 4GB左右
/**
* 教育网镜像
*
* 我们目前根据 https://github.com/mirrorz-org/oh-my-mirrorz 挑选速度前10位
*/
MirrorInfo
MirrorZ = {"mirrorz", "MirrorZ", "MirrorZ 校园网镜像站", "https://mirrors.cernet.edu.cn/", NULL},
Tuna = {"tuna", "TUNA", "清华大学开源软件镜像站", "https://mirrors.tuna.tsinghua.edu.cn/",
"https://mirrors.tuna.tsinghua.edu.cn/speedtest/1000mb.bin"},
Sjtug_Zhiyuan = {"sjtu", "SJTUG-zhiyuan", "上海交通大学致远镜像站", "https://mirrors.sjtug.sjtu.edu.cn/",
"https://mirrors.sjtug.sjtu.edu.cn/ctan" Big_File_ctan},
Zju = {"zju", "ZJU", "浙江大学开源软件镜像站", "https://mirrors.zju.edu.cn/",
"https://mirrors.zju.edu.cn/debian" Big_File_debian},
Lzuoss = {"lzu", "LZUOSS", "兰州大学开源社区镜像站", "https://mirror.lzu.edu.cn/",
"https://mirror.lzu.edu.cn/CTAN" Big_File_ctan},
Jlu = {"jlu", "JLU", "吉林大学开源镜像站", "https://mirrors.jlu.edu.cn/",
"https://mirrors.jlu.edu.cn/_static/speedtest.bin"},
Bfsu = {"bfsu", "BFSU", "北京外国语大学开源软件镜像站","https://mirrors.bfsu.edu.cn/",
"https://mirrors.bfsu.edu.cn/speedtest/1000mb.bin"},
Pku = {"pku", "PKU", "北京大学开源镜像站", "https://mirrors.pku.edu.cn/",
"https://mirrors.pku.edu.cn/debian" Big_File_debian},
Bjtu = {"bjtu", "BJTU", "北京交通大学自由与开源软件镜像站", "https://mirror.bjtu.edu.cn/",
"https://mirror.bjtu.edu.cn/archlinux" Big_File_archlinux},
Sustech = {"sustech", "SUSTech", "南方科技大学开源软件镜像站", "https://mirrors.sustech.edu.cn/",
"https://mirrors.sustech.edu.cn/site/speedtest/1000mb.bin"},
Ustc = {"ustc", "USTC", "中国科学技术大学开源镜像站", "https://mirrors.ustc.edu.cn/",
"https://mirrors.ustc.edu.cn/CTAN" Big_File_ctan},
// 速度暂时处于10位以后但是目前可用的源
Nju = {"nju", "NJU", "南京大学开源镜像站", "https://mirrors.nju.edu.cn/",
"https://mirrors.nju.edu.cn/archlinux" Big_File_archlinux};
// @ccmywish: [2023-09-05] 我只使用了不到5次重庆大学镜像站就把我的ip封杀了对用户来说封杀策略过严暂时不可靠暂时不用
//
// Cqu = {"cqu", "CQU", "重庆大学开源软件镜像站", "https://mirrors.cqu.edu.cn/",
// "https://mirrors.cqu.edu.cn/speedtest/1000mb.bin"};
/**
* 商业公司提供的源
*
* @warning 腾讯软件源中,有很多链接都已失效,请仔细检查
*/
MirrorInfo
Ali = {"ali", "Ali OPSX", "阿里巴巴开源镜像站", "https://developer.aliyun.com/mirror/",
"https://mirrors.aliyun.com/deepin-cd" Big_File_deepin},
Tencent = {"tencent", "Tencent", "腾讯软件源", "https://mirrors.tencent.com/",
"https://mirrors.cloud.tencent.com/debian" Big_File_debian},
Huawei = {"huawei", "Huawei Cloud", "华为开源镜像站", "https://mirrors.huaweicloud.com/",
"https://mirrors.huaweicloud.com/debian/" Big_File_debian },
Netease = {"netease", "Netease", "网易开源镜像站", "https://mirrors.163.com/",
"https://mirrors.163.com/deepin-cd" Big_File_deepin},
Sohu = {"sohu", "SOHU", "搜狐开源镜像站", "https://mirrors.sohu.com/",
"https://mirrors.sohu.com/deepin-cd" Big_File_deepin},
Api7 = {"api7", "api7.ai", "深圳支流科技有限公司", "https://www.apiseven.com/", NULL};
// 开源社区
MirrorInfo
RubyChina = {"rubychina", "RubyChina", "Ruby China 社区", "https://gems.ruby-china.com/",
"https://gems.ruby-china.com/rubygems/gems/nokogiri-1.15.0-java.gem"}, // 9.9 MB
NpmMirror = {"npmmirror", "npmmirror", "npmmirror (阿里云赞助)", "https://npmmirror.com/",
// 注意,这个是跳转后的地址,不确定未来会不会改变
"https://cdn.npmmirror.com/packages/%40tensorflow/tfjs/4.10.0/tfjs-4.10.0.tgz"}, // 29MB
GoProxyCN = {"goproxy.cn", "Goproxy.cn", "Goproxy.cn (七牛云赞助)", "https://goproxy.cn/",
"https://goproxy.cn/github.com/aws/aws-sdk-go/@v/v1.45.2.zip"}, // 30 MB
GoProxyIO = {"goproxy.io", "GOPROXY.IO", "GOPROXY.IO", "https://goproxy.io/",
"https://goproxy.io/github.com/aws/aws-sdk-go/@v/v1.45.2.zip"}, // 30 MB
NugetOrg = {"nuget.org", "NuGet Org", "Nuget Organization", "https://www.nuget.org/", NULL},
EmacsChina = {"emacschina", "EmacsChina", "Emacs China 社区", "https://elpamirror.emacs-china.org/", NULL};
MirrorInfo
Upstream = {"upstream", "Upstream", "上游默认源", NULL, NULL};
MirrorInfo*
available_mirrors[] = {
&MirrorZ, &Tuna, &Sjtug_Zhiyuan, &Zju, &Lzuoss, &Jlu, &Bfsu, &Pku, &Bjtu, &Sustech, &Ustc, &Nju, // &Cqu,
&Ali, &Tencent, &Huawei, &Netease, &Sohu, &Api7,
&RubyChina, &EmacsChina, &NpmMirror, &GoProxyCN, &GoProxyIO,
// 暂不支持 &NugetOrg
// 不要列出 &Upstream
};
typedef struct {
const MirrorInfo* mirror;
const char* url;
} SourceInfo;
/**
* 源信息
*
* @note 我们要求每个源最好情况下
* 1. 至少有一个教育网镜像
* 2. 至少有一个商业公司或开源社区维护的镜像
*/
/**
* 2024-04-18 更新
*
* @note
* 下面的源,并不都实现正确,
* BFSU 和 Tuna 以及 阿里的镜像都有问题会循环遍历一个gem的所有版本导致安装时间相当长
*
* @note
* 2024-04-18: @ccmywish: 华为云镜像正确可用
*
* @note 网络情况
* 若实现正确:
* 1. 目前北外最快最稳定
* 2. 腾讯挺快个别时候不稳定但稳定时能达到4.5MB甚至以上
* 3. tuna 有时快有时慢不稳定一般在3MB以下
* 4. rubychina 有时快有时慢,快时一般在 2MB以下慢时一般在1MB以下
* 5. 阿里云最不稳定,经常最慢
*/
static SourceInfo
pl_ruby_sources[] = {
{&Tencent, "https://mirrors.tencent.com/rubygems/"},
{&RubyChina, "https://gems.ruby-china.com/"},
{&Huawei, "https://mirrors.huaweicloud.com/repository/rubygems/"}
// {&Bfsu, "https://mirrors.bfsu.edu.cn/rubygems/"},
// {&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/rubygems/"},
// {&Ali, "https://mirrors.aliyun.com/rubygems/"},
},
/**
* 2024-04-18 更新
*
* @note 不要添加Zju浙大的pypi在校外访问会自动转向Tuna
*/
pl_python_sources[] = {
{&Bfsu, "https://mirrors.bfsu.edu.cn/pypi/web/simple"},
{&Lzuoss, "https://mirror.lzu.edu.cn/pypi/web/simple"},
{&Jlu, "https://mirrors.jlu.edu.cn/pypi/web/simple"},
{&Sjtug_Zhiyuan, "https://mirror.sjtu.edu.cn/pypi/web/simple"},
{&Tuna, "https://pypi.tuna.tsinghua.edu.cn/simple"},
{&Ali, "https://mirrors.aliyun.com/pypi/simple/"},
{&Tencent, "https://mirrors.cloud.tencent.com/pypi/simple"},
{&Huawei, "https://mirrors.huaweicloud.com/repository/pypi/simple"},
// {&Netease, "https://mirrors.163.com/.help/pypi.html"} // 不用24小时更新一次
},
/**
* 2024-04-18 更新
*
* Sjtug, Tuna, Lzuoss, Jlu, Bfsu, 网易,搜狐 都没有
*
* @note 腾讯软件源虽然有npm的名但名存实亡
*/
pl_nodejs_sources[] = {
{&NpmMirror, "https://registry.npmmirror.com"},
{&Huawei, "https://mirrors.huaweicloud.com/repository/npm/"},
{&Zju, "https://mirrors.zju.edu.cn/npm"}
},
/**
* 2023-09-05 更新
*
* 参考: https://help.mirrors.cernet.edu.cn/CPAN/
*/
pl_perl_sources[] = {
{&Bfsu, "https://mirrors.bfsu.edu.cn/CPAN/"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/CPAN/"},
{&Bjtu, "https://mirror.bjtu.edu.cn/cpan/"},
{&Ali, "https://mirrors.aliyun.com/CPAN/"},
{&Lzuoss, "https://mirror.lzu.edu.cn/CPAN/"}
},
/**
* 2024-04-18 更新
*
* @note 缺少教育网或开源社区软件源
*/
pl_php_sources[] = {
{&Ali, "https://mirrors.aliyun.com/composer/"},
{&Tencent, "https://mirrors.tencent.com/composer/"},
{&Huawei, "https://mirrors.huaweicloud.com/repository/php/"}
},
/**
* 2023-09-27 更新
*
* @note 目前只有唯一一个源
*/
pl_lua_sources[] = {
{&Api7, "https://luarocks.cn"},
},
/**
* 2024-04-18 更新
*
* @note 缺少教育网软件源
*/
pl_go_sources[] = {
{&GoProxyCN, "https://goproxy.cn"},
{&Ali, "https://mirrors.aliyun.com/goproxy/"},
{&Huawei, "https://mirrors.huaweicloud.com/goproxy/"},
{&GoProxyIO, "https://goproxy.io"}
},
/**
* 2023-09-05 更新
*
* @note 缺少商业公司或开源社区软件源
*
* @note 以下都支持稀疏索引,我们换源时都将默认添加 `sparse+`
*/
pl_rust_sources[] = {
{&Sjtug_Zhiyuan, "https://mirrors.sjtug.sjtu.edu.cn/crates.io-index/"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/crates.io-index/"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/crates.io-index/"},
{&Ustc, "https://mirrors.ustc.edu.cn/crates.io-index/"},
},
/**
* 2024-04-18 更新
*
* @note 缺少教育网或开源社区软件源
*/
pl_java_sources[] = {
{&Ali, "https://maven.aliyun.com/repository/public/"},
{&Huawei, "https://mirrors.huaweicloud.com/repository/maven/"},
{&Netease, "http://mirrors.163.com/maven/repository/maven-public/"} // 网易的24小时更新一次
},
/**
* 2023-09-10 更新
*
* @note 不太好换,且用户可能不多,我们暂时只给用户提供文档
*/
pl_clojure_sources[] = {
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/help/clojars/"},
{&Ustc, "https://mirrors.ustc.edu.cn/help/clojars.html"}
},
/**
* 2024-04-18 更新
*
* @note 暂时未实现该换源功能,可参照
* https://mirrors.huaweicloud.com/mirrorDetail/5ebf85de07b41baf6d0882ab?mirrorName=nuget&catalog=language
*/
pl_dotnet_sources[] = {
{&NugetOrg, "https://www.nuget.org/api/v2/"},
{&Huawei, "https://mirrors.huaweicloud.com/repository/nuget/v3"}
},
/**
* 2023-09-10 更新
*
* @note 我们这里挑选的必须也支持 Flutter
*
* 我们将会在setsrc函数中生成
* 1. https://mirrors.tuna.tsinghua.edu.cn/dart-pub
* 2. https://mirrors.tuna.tsinghua.edu.cn/flutter
*/
pl_dart_sources[] = {
// {&Sjtug_Zhiyuan, "https://mirror.sjtu.edu.cn/"}, // 不确定SJTUG的flutter镜像给的对不对
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/"},
{&Tencent, "https://mirrors.cloud.tencent.com/"},
{&Nju, "https://mirror.nju.edu.cn/"}
},
/**
* 2023-09-10 更新
*/
pl_haskell_sources[] = {
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/hackage"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/hackage"},
{&Nju, "https://mirror.nju.edu.cn/hackage"},
{&Ustc, "https://mirrors.ustc.edu.cn/hackage"}
},
/**
* 2023-09-15 更新
*/
pl_ocaml_sources[] = {
{&Sjtug_Zhiyuan, "https://mirrors.sjtug.sjtu.edu.cn/git/opam-repository.git"}
},
/**
* 2023-09-04 更新
*
* @note 以下注释的是不含有bioconductor的镜像站
* 我们在换cran的同时也直接帮助用户换bioconductor
*/
pl_r_sources[] = {
{&Sjtug_Zhiyuan, "https://mirrors.sjtug.sjtu.edu.cn/cran/"},
// {&Ali, "https://mirrors.aliyun.com/CRAN/"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/CRAN/"},
// {&Sustech, "https://mirrors.sustech.edu.cn/CRAN"},
// {&Bfsu, "https://mirrors.bfsu.edu.cn/CRAN/"},
// {&Bjtu, "https://mirror.bjtu.edu.cn/cran/"},
},
/**
* 2023-09-05 更新
*
* @note 缺少商业公司或开源社区软件源
*/
pl_julia_sources[] = {
{&Sjtug_Zhiyuan, "https://mirrors.sjtug.sjtu.edu.cn/julia"},
{&Pku, "https://mirrors.pku.edu.cn/julia"},
{&Nju, "https://mirror.nju.edu.cn/julia"}
};
/**
* 2024-04-18 更新
*/
static SourceInfo
os_ubuntu_sources[] = {
{&Ali, "https://mirrors.aliyun.com/ubuntu"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/ubuntu"},
{&Ustc, "https://mirrors.ustc.edu.cn/ubuntu"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/ubuntu"},
{&Tencent, "https://mirrors.tencent.com/ubuntu"},
{&Huawei, "https://mirrors.huaweicloud.com/ubuntu"},
{&Netease, "https://mirrors.163.com/ubuntu"},
{&Sohu, "https://mirrors.sohu.com/ubuntu"}
},
/**
* 2023-09-29 更新
*
* @note: 实际上镜像站里的内容和Ubuntu的不太一样
*/
os_mint_sources[] = {
{&MirrorZ, "https://mirrors.cernet.edu.cn/linuxmint/"},
{&Ali, "http://mirrors.aliyun.com/linuxmint-packages/"},
{&Netease, "https://mirrors.163.com/linuxmint/packages/"},
},
/**
* 2023-09-06 更新
*
* TODO: 1. 源并不完整,且未经测试是否有效
*/
os_deepin_sources[] = {
{&Ali, "https://mirrors.aliyun.com/deepin"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/deepin"},
{&Ustc, "https://mirrors.ustc.edu.cn/deepin"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/deepin"},
{&Tencent, "https://mirrors.tencent.com/deepin"},
{&Netease, "https://mirrors.163.com/deepin"},
{&Sohu, "https://mirrors.sohu.com/deepin"}
},
/**
* 2023-09-01 更新
*
* TODO: 1. 源并不完整,且未经测试是否有效
*/
os_debian_sources[] = {
{&Ali, "https://mirrors.aliyun.com/debian"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/debian"},
{&Ustc, "https://mirrors.ustc.edu.cn/debian"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/debian"},
{&Tencent, "https://mirrors.tencent.com/debian"},
{&Netease, "https://mirrors.163.com/debian"},
{&Sohu, "https://mirrors.sohu.com/debian"}
},
/**
* 2023-09-02 更新
*
* TODO: 1. 源并不完整,且未经测试是否有效
*/
os_fedora_sources[] = {
{&Ali, "https://mirrors.aliyun.com/fedora"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/fedora"},
{&Ustc, "https://mirrors.ustc.edu.cn/fedora"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/fedora"},
{&Tencent, "https://mirrors.tencent.com/fedora"},
{&Netease, "https://mirrors.163.com/fedora"},
{&Sohu, "https://mirrors.sohu.com/fedora"}
},
/**
* 2024-04-18 更新
*
* TODO: 未经测试是否有效
*/
os_kali_sources[] = {
{&Ali, "https://mirrors.aliyun.com/kali"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/kali"},
{&Ustc, "https://mirrors.ustc.edu.cn/kali"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/kali"},
{&Tencent, "https://mirrors.tencent.com/kali"},
{&Huawei, "https://mirrors.huaweicloud.com/kali"},
{&Netease, "https://mirrors.163.com/kali"},
{&Sohu, "https://mirrors.sohu.com/kali"}
},
/**
* 2024-04-18 更新
*
* TODO: 源并不完整,且未经测试是否有效
*/
os_arch_sources[] = {
{&Ali, "https://mirrors.aliyun.com/"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/"},
{&Ustc, "https://mirrors.ustc.edu.cn/"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/"},
{&Tencent, "https://mirrors.tencent.com/"},
{&Huawei, "https://mirrors.huaweicloud.com/archlinux/"},
{&Netease, "https://mirrors.163.com/"},
{&Sohu, "https://mirrors.sohu.com/"}
},
/**
* 2023-09-05 更新
*
* TODO: 1. 源并不完整,且未经测试是否有效
*/
os_gentoo_sources[] = {
{&Ali, "mirrors.aliyun.com"},
{&Bfsu, "mirrors.bfsu.edu.cn"},
{&Ustc, "mirrors.ustc.edu.cn"},
{&Tuna, "mirrors.tuna.tsinghua.edu.cn"},
{&Tencent, "mirrors.tencent.com"},
{&Netease, "mirrors.163.com"},
{&Sohu, "mirrors.sohu.com"}
},
/**
* 2023-09-17 更新
*
* TODO: 1. 源并不完整,且未经测试是否有效
*/
os_opensuse_sources[] = {
{&Ali, "https://mirrors.aliyun.com/opensuse"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/opensuse"},
{&Ustc, "https://mirrors.ustc.edu.cn/opensuse"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/opensuse"},
{&Tencent, "https://mirrors.tencent.com/opensuse"},
{&Netease, "https://mirrors.163.com/opensuse"},
{&Sohu, "https://mirrors.sohu.com/opensuse"}
},
/**
* 2024-04-18 更新
*
* TODO: 源并不完整,且未经测试是否有效
*/
os_msys2_sources[] = {
{&Ali, "https://mirrors.aliyun.com/msys2"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/msys2"},
{&Ustc, "https://mirrors.ustc.edu.cn/msys2"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/msys2"},
{&Tencent, "https://mirrors.tencent.com/msys2"},
{&Huawei, "https://mirrors.huaweicloud.com/msys2"},
{&Netease, "https://mirrors.163.com/msys2"},
{&Sohu, "https://mirrors.sohu.com/msys2"}
},
/**
* 2023-09-24 更新
*/
os_rocky_sources[] = {
{&Sjtug_Zhiyuan, "https://mirror.sjtu.edu.cn/rocky"},
{&Sustech, "https://mirrors.sustech.edu.cn/rocky-linux"},
{&Zju, "https://mirrors.zju.edu.cn/rocky"},
{&Lzuoss, "https://mirror.lzu.edu.cn/rocky"},
{&Sohu, "https://mirrors.sohu.com/Rocky"},
{&Netease, "https://mirrors.163.com/rocky"},
{&Ali, "https://mirrors.aliyun.com/rockylinux"},
},
/**
* 2024-04-18 更新
*/
os_alpine_sources[] = {
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/alpine"},
{&Sjtug_Zhiyuan, "https://mirrors.sjtug.sjtu.edu.cn/alpine"},
{&Sustech, "https://mirrors.sustech.edu.cn/alpine"},
{&Zju, "https://mirrors.zju.edu.cn/alpine"},
{&Lzuoss, "https://mirror.lzu.edu.cn/alpine"},
{&Ali, "https://mirrors.aliyun.com/alpine"},
{&Tencent, "https://mirrors.cloud.tencent.com/alpine"},
{&Huawei, "https://mirrors.huaweicloud.com/alpine/"}
},
/**
* 2023-09-24 更新
*/
os_void_sources[] = {
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/voidlinux"},
{&Sjtug_Zhiyuan, "https://mirror.sjtu.edu.cn/voidlinux"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/voidlinux"}
},
/**
* 2023-09-29 更新
*/
os_solus_sources[] = {
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/solus/packages/shannon/eopkg-index.xml.xz"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/solus/packages/shannon/eopkg-index.xml.xz"},
{&Nju, "https://mirror.nju.edu.cn/solus/packages/shannon/eopkg-index.xml.xz"}
},
/**
* 2023-09-29 更新
*/
os_linuxlite_sources[] = {
{&Sjtug_Zhiyuan, "https://mirrors.sjtug.sjtu.edu.cn/linuxliteos/"}
},
/**
* 2023-09-29 更新
*/
os_trisquel_sources[] = {
{&Ali, "https://mirrors.aliyun.com/trisquel/"},
{&MirrorZ, "https://mirrors.cernet.edu.cn/trisquel/"},
{&Nju, "https://mirror.nju.edu.cn/trisquel/"},
{&Ustc, "https://mirrors.ustc.edu.cn/trisquel/"}
},
/**
* 2023-09-29 更新
*/
os_raspberrypi_sources[] = {
{&MirrorZ, "https://help.mirrors.cernet.edu.cn/raspberrypi/"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/raspberrypi/"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/raspberrypi/"},
{&Ustc, "https://mirrors.ustc.edu.cn/raspberrypi/"},
{&Sjtug_Zhiyuan, "https://mirrors.sjtug.sjtu.edu.cn/raspberrypi/"},
{&Sustech, "https://mirrors.sustech.edu.cn/raspberrypi/"}
},
/**
* 2023-09-27 更新
*
* @note 该源需要 FreeBSD 中文社区积极参与维护
*
* @ccmywish: [2023-09-24] 以下三个USTC, NJU, Netease 均维护了 freebsd-pkg freebsd-ports
* @ccmywish: [2023-09-27] 请务必保持Nju前面有至少一个镜像原因请查看 freebsd 的换源函数
*/
os_freebsd_sources[] = {
{&Ustc, "mirrors.ustc.edu.cn"},
{&Nju, "mirror.nju.edu.cn"},
{&Netease, "mirrors.163.com"},
},
/**
* 2023-09-05 更新
*
* TODO: 1. 源并不完整,且未经测试是否有效
*/
os_netbsd_sources[] = {
{&Ali, "https://mirrors.aliyun.com/pkgsrc/packages/NetBSD/"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/pkgsrc/packages/NetBSD/"},
{&Ustc, "https://mirrors.ustc.edu.cn/pkgsrc/packages/NetBSD/"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/pkgsrc/packages/NetBSD/"},
{&Tencent, "https://mirrors.tencent.com/pkgsrc/packages/NetBSD/"},
{&Netease, "https://mirrors.163.com/pkgsrc/packages/NetBSD/"},
{&Sohu, "https://mirrors.sohu.com/pkgsrc/packages/NetBSD/"}
},
/**
* 2023-09-02 更新
*
* TODO: 1. 源并不完整,且未经测试是否有效
*/
os_openbsd_sources[] = {
{&Ali, "https://mirrors.aliyun.com/OpenBSD/"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/OpenBSD/"},
{&Ustc, "https://mirrors.ustc.edu.cn/OpenBSD/"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/OpenBSD/"},
{&Tencent, "https://mirrors.tencent.com/OpenBSD/"},
{&Netease, "https://mirrors.163.com/OpenBSD/"},
{&Sohu, "https://mirrors.sohu.com/OpenBSD/"}
},
/**
* 2023-09-06 更新
*
* TODO: 1. 源并不完整,且未经测试是否有效
*/
os_openeuler_sources[] = {
{&Ali, "https://mirrors.aliyun.com/openeuler/"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/openeuler/"},
{&Ustc, "https://mirrors.ustc.edu.cn/openeuler/"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/openeuler/"},
{&Tencent, "https://mirrors.tencent.com/openeuler/"},
{&Netease, "https://mirrors.163.com/openeuler/"},
{&Sohu, "https://mirrors.sohu.com/openeuler/"}
},
/**
* 2023-09-29 更新
*/
os_openkylin_sources[] = {
{&Upstream, "https://archive.openkylin.top/openkylin/"},
{&Ali, "https://mirrors.aliyun.com/openkylin/"},
{&Netease, "https://mirrors.163.com/openkylin/"},
},
/**
* 2024-04-18 更新
*
* TODO: 未经测试是否有效
*/
os_ros_sources[] = {
{&Ali, "https://mirrors.aliyun.com"},
{&Bfsu, "https://mirrors.bfsu.edu.cn"},
{&Ustc, "https://mirrors.ustc.edu.cn"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn"},
{&Tencent, "https://mirrors.tencent.com"},
{&Huawei, "https://mirrors.huaweicloud.com"},
{&Netease, "https://mirrors.163.com"},
{&Sohu, "https://mirrors.sohu.com"}
};
/**
* 2023-09-10 更新
*
* TODO: 1. 暂未添加商业公司源
*/
static SourceInfo
wr_tex_sources[] = {
{&Sjtug_Zhiyuan, "https://mirrors.sjtug.sjtu.edu.cn/ctan/systems/texlive/tlnet"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/tlnet"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/CTAN/systems/texlive/tlnet"},
{&Lzuoss, "https://mirror.lzu.edu.cn/CTAN/systems/texlive/tlnet"},
{&Jlu, "https://mirrors.jlu.edu.cn/CTAN/systems/texlive/tlnet"},
{&Sustech, "https://mirrors.sustech.edu.cn/CTAN/systems/texlive/tlnet"}
},
/**
* 2023-09-10 更新
*
* @note Emacs用户往往只需要一次性换源只会极少次调用 chsrc我们只给用户提供文档
*/
wr_emacs_sources[] = {
{&Sjtug_Zhiyuan, "https://mirrors.sjtug.sjtu.edu.cn/docs/emacs-elpa"},
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/help/elpa/"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/help/elpa/"},
{&Ustc, "https://mirrors.ustc.edu.cn/help/elpa.html"},
{&Zju, "https://mirrors.zju.edu.cn/docs/elpa/"},
{&EmacsChina, "https://elpamirror.emacs-china.org/"}
},
/**
* 2023-09-10 更新
*
* @note 1. 这些链接将会在setsrc函数中补充完整
* 2. 不确定 Sustech 能否工作
*/
wr_brew_sources[] = {
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/"},
{&Zju, "https://mirrors.zju.edu.cn/"},
{&Sustech, "https://mirrors.sustech.edu.cn/"}
},
/**
* 2023-09-11 更新
*
* @note 目前只有一个源
*/
wr_flathub_sources[] = {
{&Sjtug_Zhiyuan, "https://mirror.sjtu.edu.cn/flathub"},
},
/**
* 2023-09-22 更新
*
* @note 1. 目前只有一个源
* 2. 这些链接将会在setsrc函数中补充完整
*/
wr_nix_sources[] = {
{&Bfsu, "https://mirrors.bfsu.edu.cn/nix-channels/"}
},
/**
* 2023-09-11 更新
*
* @note 目前只有一个源
*/
wr_guix_sources[] = {
{&Sjtug_Zhiyuan, "https://mirror.sjtu.edu.cn/git/guix.git"}
},
/**
* 2023-09-10 更新
*
* @note 这些链接将会在setsrc函数中补充完整
*/
wr_anaconda_sources[] = {
{&Tuna, "https://mirrors.tuna.tsinghua.edu.cn/anaconda/"},
{&Bfsu, "https://mirrors.bfsu.edu.cn/anaconda/"},
{&Zju, "https://mirrors.zju.edu.cn/anaconda/"},
{&Sjtug_Zhiyuan, "https://mirror.sjtu.edu.cn/anaconda"}
};
#define def_sources_n(t) const size_t t##_sources_n = xy_arylen(t##_sources)
def_sources_n(pl_ruby); def_sources_n(pl_python); def_sources_n(pl_nodejs);
def_sources_n(pl_perl); def_sources_n(pl_php); def_sources_n(pl_lua);
def_sources_n(pl_go); def_sources_n(pl_rust);
def_sources_n(pl_java); def_sources_n(pl_clojure);
def_sources_n(pl_dotnet); def_sources_n(pl_dart); def_sources_n(pl_haskell);
def_sources_n(pl_ocaml);
def_sources_n(pl_r); def_sources_n(pl_julia);
def_sources_n(os_ubuntu); def_sources_n(os_mint);
def_sources_n(os_debian); def_sources_n(os_fedora);
def_sources_n(os_kali); def_sources_n(os_opensuse);
def_sources_n(os_arch); def_sources_n(os_msys2); def_sources_n(os_gentoo);
def_sources_n(os_alpine); def_sources_n(os_rocky); def_sources_n(os_void);
def_sources_n(os_solus);
def_sources_n(os_trisquel); def_sources_n(os_linuxlite); def_sources_n(os_raspberrypi);
def_sources_n(os_freebsd); def_sources_n(os_netbsd); def_sources_n(os_openbsd);
def_sources_n(os_deepin); def_sources_n(os_openeuler); def_sources_n(os_openkylin);
def_sources_n(os_ros);
def_sources_n(wr_brew); def_sources_n(wr_flathub);
def_sources_n(wr_nix); def_sources_n(wr_guix);
def_sources_n(wr_tex); def_sources_n(wr_emacs);
def_sources_n(wr_anaconda);

612
include/xy.h Normal file
View File

@@ -0,0 +1,612 @@
/** ------------------------------------------------------------
* File : xy.h
* License : MIT
* Authors : Aoran Zeng <ccmywish@qq.com>
* Created on : <2023-08-28>
* Last modified : <2024-04-18>
*
* xy:
*
* y = f(x)
*
* Corss-Platform C utilities for CLI applications in Ruby flavor
*
* 该文件采用 MIT 许可证,请查阅 LICENSE.txt 文件
* ------------------------------------------------------------*/
#ifndef XY_H
#define XY_H
#define XY_Version "v0.1.1-2024/04/18"
#define XY_Maintain_URL "https://gitee.com/RubyMetric/chsrc/blob/main/xy.h"
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// #define NDEBUG
#ifdef _WIN32
#define xy_on_windows true
#define xy_on_linux false
#define xy_on_macos false
#define xy_on_bsd false
#define xy_os_devnull "nul"
#include <windows.h>
#define xy_useutf8() SetConsoleOutputCP (65001)
#elif defined(__linux__) || defined(__linux)
#define xy_on_windows false
#define xy_on_linux true
#define xy_on_macos false
#define xy_on_bsd false
#define xy_os_devnull "/dev/null"
#define xy_useutf8()
#elif defined(__APPLE__)
#define xy_on_windows false
#define xy_on_linux false
#define xy_on_macos true
#define xy_on_bsd false
#define xy_os_devnull "/dev/null"
#define xy_useutf8()
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
#define xy_on_windows false
#define xy_on_linux false
#define xy_on_macos false
#define xy_on_bsd true
#define xy_os_devnull "/dev/null"
#define xy_useutf8()
#endif
void
putf (double n)
{
printf ("%f\n", n);
}
void
puti (long long n)
{
printf ("%lld\n", n);
}
void
putb (bool n)
{
if (n)
puts ("true");
else
puts ("false");
}
void
print (char *s)
{
printf ("%s", s);
}
void
println (char *s)
{
printf ("%s\n", s);
}
#define xy_arylen(x) (sizeof (x) / sizeof (x[0]))
#define assert_str(a, b) assert (xy_streql ((a), (b)))
static inline void *
xy_malloc0 (size_t size)
{
void *ptr = malloc (size);
memset (ptr, 0, size);
return ptr;
}
#define XY_Log_Info 00001
#define XY_Log_Success 00001 << 1
#define XY_Log_Warn 00001 << 2
#define XY_Log_Error 00001 << 3
#define xy_success(str) _xy_log (XY_Log_Success, str)
#define xy_info(str) _xy_log (XY_Log_Info, str)
#define xy_warn(str) _xy_log (XY_Log_Warn, str)
#define xy_error(str) _xy_log (XY_Log_Error, str)
static void
_xy_log (int level, const char *str)
{
char *color_fmt_str = NULL;
bool to_stderr = false;
if (level & XY_Log_Info)
{
color_fmt_str = "\033[34m%s\033[0m"; // 蓝色
}
else if (level & XY_Log_Success)
{
color_fmt_str = "\033[32m%s\033[0m"; // 绿色
}
else if (level & XY_Log_Warn)
{
color_fmt_str = "\033[33m%s\033[0m\n"; // 黄色
to_stderr = true;
}
else if (level & XY_Log_Error)
{
color_fmt_str = "\033[31m%s\033[0m\n"; // 红色
to_stderr = true;
}
else
{
// xy_assert ("CAN'T REACH!");
}
// -2 把中间%s减掉
size_t len = strlen (color_fmt_str) - 2;
char *buf = malloc (strlen (str) + len + 1);
sprintf (buf, color_fmt_str, str);
if (to_stderr)
{
fprintf (stderr, "%s", buf);
}
else
{
puts (buf);
}
free (buf);
}
/**
* 将str中所有的pat字符串替换成replace返回一个全新的字符串
*/
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;
}
static char *
xy_2strjoin (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;
}
static char *
xy_strjoin (unsigned int count, ...)
{
size_t al_fixed = 128;
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);
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_error ("xy: No availble memory!");
return NULL;
}
strcpy (cur, str);
// puts(ret);
cur += strlen (str);
}
va_end (args);
*cur = '\0';
return ret;
}
static char *
xy_strdup (const char *str)
{
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;
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;
}
// -2 把中间%s减掉
size_t 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)
{
return strcmp (str1, str2) == 0 ? true : false;
}
static char *
xy_str_to_quietcmd (const char *cmd)
{
char *ret = NULL;
#ifdef _WIN32
ret = xy_2strjoin (cmd, " >nul 2>nul ");
#else
ret = xy_2strjoin (cmd, " 1>/dev/null 2>&1 ");
#endif
return ret;
}
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;
}
static bool
xy_str_start_with (const char *str, const char *prefix)
{
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;
}
static char *
xy_str_delete_prefix (const char *str, const char *prefix)
{
char *new = xy_strdup (str);
bool yes = xy_str_start_with (str, prefix);
if (!yes)
return new;
size_t len = strlen (prefix);
char *cur = new + len;
return cur;
}
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;
}
static char *
xy_str_strip (const char *str)
{
char *new = xy_strdup (str);
while (strchr ("\n\r\v\t\f ", new[0]))
{
new += 1;
}
size_t len = strlen (new);
char *last = new + len - 1;
while (strchr ("\n\r\v\t\f ", *last))
{
*last = '\0';
last -= 1;
}
return new;
}
/**
* 执行cmd返回其最后某行输出结果
*
* @param cmd 要执行的命令
* @param n 命令打印的结果行0 表示最后一行n (n>0) 表示第n行
* @param func 对读取的行执行函数
*
* @note 返回的字符串最后面可能有换行符号
*/
static char *
xy_getcmd (const char *cmd, unsigned long n, void (*func) (const char *))
{
const int size = 512;
char *buf = (char *)malloc (size);
FILE *stream = popen (cmd, "r");
if (stream == NULL)
{
fprintf (stderr, "xy: 命令执行失败\n");
return NULL;
}
char *ret = NULL;
unsigned long count = 0;
while (true)
{
if (NULL == fgets (buf, size, stream))
break;
ret = buf;
count += 1;
if (n == count)
break;
if (func)
{
func (buf);
}
}
pclose (stream);
return ret;
}
#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;
}
#define xy_win_powershell_profile _xy_win_powershell_profile ()
#define xy_win_powershellv5_profile _xy_win_powershellv5_profile ()
static char *
_xy_win_powershell_profile ()
{
return xy_2strjoin (
xy_os_home, "\\Documents\\PowerShell\\Microsoft.PowerShell_profile.ps1");
}
char *
_xy_win_powershellv5_profile ()
{
return xy_2strjoin (
xy_os_home,
"\\Documents\\WindowsPowerShell\\Microsoft.PowerShell_profile.ps1");
}
/**
* @note Windows上`path` 不要夹带变量名,因为最终 access() 不会帮你转换
*/
static bool
xy_file_exist (const char *path)
{
const char *newpath = path;
if (xy_on_windows)
{
if (xy_str_start_with (path, "~"))
{
newpath = xy_2strjoin (xy_os_home, path + 1);
}
}
return access (newpath, 0) ? false : true;
}
/**
* 该函数即使在非Windows下也可调用作用是删除路径左右两边多出来的空白符
*/
static char *
xy_uniform_path (const char *path)
{
char *new = xy_str_strip (path); // 防止开发者多写了空白符
// 这个函数仅在Windows上才进行替换
if (xy_on_windows)
{
if (xy_str_start_with (new, "~/"))
{
// 或 %USERPROFILE%
new = xy_strjoin (3, xy_os_home, "\\",
xy_str_delete_prefix (new, "~/"));
}
new = xy_str_gsub (new, "/", "\\");
}
return new;
}
static char *
xy_parent_dir (const char *path)
{
char *dir = xy_uniform_path (path);
char *last = NULL;
if (xy_on_windows)
{
last = strrchr (dir, '\\');
*last = '\0';
}
else
{
last = strrchr (dir, '/');
*last = '\0';
}
return dir;
}
#endif