Files
scc/libs/argparse/src/argparse_print.c
T
zzy 630e22b73b feat(argparse): 添加命令行参数约束和错误处理功能
- 添加了命令行参数约束相关数据结构定义
- 新增错误上下文字段用于更好的错误提示
- 实现了参数验证功能,包括必需参数检查和值选择验证
- 改进错误处理流程,支持添加帮助信息和使用说明
- 优化调试输出格式,增加更多错误场景的处理

fix(parser): 修复语义分析器资源释放问题

- 在scc_sema_drop函数中添加空指针检查,避免空指针释放导致崩溃

refactor(dump): 重构AST节点转储实现

- 将树形转储上下文重构为更简洁的数据结构
- 修改转储回调函数签名以支持更好的缓冲区管理
- 优化内存拷贝操作,提高转储性能

style(amd64): 移除未使用的变量声明

- 删除scc_mcode_amd64_mov_r64_m64_sib函数中未使用的disp8变量
2026-04-11 11:42:31 +08:00

249 lines
8.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <argparse.h>
// 帮助信息处理函数
enum {
ARGPARSE_USAGE,
ARGPARSE_OPTION,
ARGPARSE_COMMAND,
ARGPARSE_ARGUMENT,
ARGPARSE_SHOW_ARG,
ARGPARSE_SHOW_OPT,
ARGPARSE_SHOW_CMD,
ARGPARSE_SHOW_HELP_MSG,
ARGPRASE_USING_HELP_HINT,
ARGPARSE_UNKNOWN_ARGUMENT,
ARGPARSE_INVALID_VALUE_FOR_OPTION,
ARGPARSE_OPTION_MISSING_VALUE,
ARGPARSE_DID_YOU_MEAN,
};
static const char *fmt_en[] = {
[ARGPARSE_USAGE] = "Usage: %s",
[ARGPARSE_OPTION] = " [Options]",
[ARGPARSE_COMMAND] = " [Commands]",
[ARGPARSE_SHOW_ARG] = "Arguments:\n",
[ARGPARSE_SHOW_OPT] = "Options:\n",
[ARGPARSE_SHOW_CMD] = "Commands:\n",
[ARGPARSE_SHOW_HELP_MSG] = "Show this help message and exit",
[ARGPRASE_USING_HELP_HINT] =
"Using '-h' or '--help' to get more information\n",
[ARGPARSE_UNKNOWN_ARGUMENT] = "Unknown argument '%s'\n",
[ARGPARSE_INVALID_VALUE_FOR_OPTION] = "Invalid value for option '%s'\n",
[ARGPARSE_OPTION_MISSING_VALUE] = "Option '%s' missing value\n",
[ARGPARSE_DID_YOU_MEAN] = "Did you mean: '%s'?\n",
};
static const char *fmt_zh[] = {
[ARGPARSE_USAGE] = "用法: %s",
[ARGPARSE_OPTION] = " [选项]",
[ARGPARSE_COMMAND] = " [命令]",
[ARGPARSE_SHOW_ARG] = "参数:\n",
[ARGPARSE_SHOW_OPT] = "选项:\n",
[ARGPARSE_SHOW_CMD] = "命令:\n",
[ARGPARSE_SHOW_HELP_MSG] = "显示帮助信息并退出",
[ARGPRASE_USING_HELP_HINT] = "使用 '-h' 或者 '--help' 获取更多信息\n",
[ARGPARSE_UNKNOWN_ARGUMENT] = "未知的参数 '%s'\n",
[ARGPARSE_INVALID_VALUE_FOR_OPTION] = "无效的选项值 '%s'\n",
[ARGPARSE_OPTION_MISSING_VALUE] = "选项 '%s' 缺少值\n",
[ARGPARSE_DID_YOU_MEAN] = "您是不是想要输入: '%s'?\n",
};
/**
* @brief 计算两个字符串的编辑距离(Levenshtein距离)
* @param s1 字符串1(非空,以'\0'结尾)
* @param s2 字符串2(非空,以'\0'结尾)
* @return 编辑距离,内存分配失败返回 -1
*/
static int scc_levenshtein(const char *s1, const char *s2) {
usize len1 = scc_strlen(s1);
usize len2 = scc_strlen(s2);
// 保证 len1 >= len2 以减少内存占用
if (len1 < len2) {
const char *tmp = s1;
s1 = s2;
s2 = tmp;
usize tlen = len1;
len1 = len2;
len2 = tlen;
}
// 分配滚动数组(只需 len2+1 个 int)
int *dp = (int *)scc_malloc(sizeof(int) * (len2 + 1));
if (!dp)
return -1;
// 初始化第0行
for (usize j = 0; j <= len2; ++j)
dp[j] = (int)j;
for (usize i = 1; i <= len1; ++i) {
int prev = dp[0];
dp[0] = (int)i;
for (usize j = 1; j <= len2; ++j) {
int temp = dp[j];
int cost = (s1[i - 1] == s2[j - 1]) ? 0 : 1;
dp[j] = scc_min(scc_min(dp[j] + 1, dp[j - 1] + 1), prev + cost);
prev = temp;
}
}
int dist = dp[len2];
scc_free(dp);
return dist;
}
static void print_usage(scc_argparse_t *parser, scc_argparse_cmd_t *cmd) {
const char **lines =
(parser->lang == SCC_ARGPARSE_LANG_ZH) ? fmt_zh : fmt_en;
scc_printf(lines[ARGPARSE_USAGE],
cmd->name ? cmd->name : parser->prog_name);
if (scc_vec_size(cmd->opts) > 0)
scc_printf(lines[ARGPARSE_OPTION]);
scc_vec_foreach(cmd->args, i) {
scc_argparse_arg_t *arg = &scc_vec_at(cmd->args, i);
scc_printf(arg->spec.flag_required ? " <%s>" : " [%s]", arg->name);
}
if (scc_vec_size(cmd->subcmds) > 0)
scc_printf(lines[ARGPARSE_COMMAND]);
scc_printf("\n\n");
}
void scc_argparse_print_help(scc_argparse_t *parser, scc_argparse_cmd_t *cmd) {
const char **lines =
(parser->lang == SCC_ARGPARSE_LANG_ZH) ? fmt_zh : fmt_en;
print_usage(parser, cmd);
if (cmd->description)
scc_printf("%s\n\n", cmd->description);
if (scc_vec_size(cmd->args) > 0) {
scc_printf(lines[ARGPARSE_SHOW_ARG]);
scc_vec_foreach(cmd->args, i) {
scc_argparse_arg_t *arg = &scc_vec_at(cmd->args, i);
scc_printf(" %-20s %s", arg->name,
arg->description ? arg->description : "");
// if (!arg->spec.required && arg->spec.flags.has_default)
// scc_printf(" (default: %s)", arg->spec.default_value);
scc_printf("\n");
}
scc_printf("\n");
}
if (scc_vec_size(cmd->opts) > 0) {
scc_printf(lines[ARGPARSE_SHOW_OPT]);
scc_vec_foreach(cmd->opts, i) {
scc_argparse_opt_t *opt = &scc_vec_at(cmd->opts, i);
if (opt->spec.flag_hidden)
continue;
if (opt->short_name == 'h')
opt->description = lines[ARGPARSE_SHOW_HELP_MSG];
char buf[64];
int pos = 0;
if (opt->short_name) {
buf[pos++] = '-';
buf[pos++] = opt->short_name;
if (opt->long_name) {
buf[pos++] = ',';
buf[pos++] = ' ';
}
}
if (opt->long_name) {
buf[pos++] = '-';
buf[pos++] = '-';
for (const char *p = opt->long_name; *p; ++p)
buf[pos++] = *p;
}
buf[pos] = '\0';
scc_printf(" %-25s %s", buf,
opt->description ? opt->description : "");
// if (opt->spec.default_value)
// scc_printf(" (default: %s)", opt->spec.default_value);
scc_printf("\n");
}
scc_printf("\n");
}
if (scc_vec_size(cmd->subcmds) > 0) {
scc_printf(lines[ARGPARSE_SHOW_CMD]);
scc_vec_foreach(cmd->subcmds, i) {
scc_argparse_cmd_t *sub = &scc_vec_at(cmd->subcmds, i);
scc_printf(" %-20s %s\n", sub->name,
sub->description ? sub->description : "");
}
scc_printf("\n");
}
if (parser->epilog)
scc_printf("%s\n", parser->epilog);
}
const char *scc_argparse_find_similar_arg(scc_argparse_cmd_t *cmd,
const char *arg) {
if (arg == nullptr || cmd == nullptr) {
return nullptr;
}
if (arg[0] == '-' && arg[1] == '-' && arg[2] != '\0') {
// opt arg
scc_vec_foreach(cmd->opts, i) {
if (scc_levenshtein(arg + 2, scc_vec_at(cmd->opts, i).long_name) <=
2) {
return scc_vec_at(cmd->opts, i).long_name;
}
}
} else {
// subcmd arg
scc_vec_foreach(cmd->subcmds, i) {
if (scc_levenshtein(arg, scc_vec_at(cmd->subcmds, i).name) <= 2) {
return scc_vec_at(cmd->subcmds, i).name;
}
}
}
return 0;
}
void scc_argparse_print_error(scc_argparse_context_t *ctx,
scc_argparse_t *parser, scc_argparse_err_t err) {
const char **lines =
(parser->lang == SCC_ARGPARSE_LANG_ZH) ? fmt_zh : fmt_en;
switch (err) {
case SCC_ARGPARSE_ERR_INVALID_ARG:
case SCC_ARGPARSE_ERR_INVALID_VALUE:
scc_printf(lines[ARGPARSE_INVALID_VALUE_FOR_OPTION], ctx->err_ctx);
break;
case SCC_ARGPARSE_ERR_MISSING_ARG:
case SCC_ARGPARSE_ERR_MISSING_VALUE:
scc_printf(lines[ARGPARSE_OPTION_MISSING_VALUE], ctx->err_ctx);
break;
case SCC_ARGPARSE_ERR_UNKNOWN_ARG:
case SCC_ARGPARSE_ERR_UNKNOWN_VALUE:
scc_printf(lines[ARGPARSE_UNKNOWN_ARGUMENT], ctx->result.raw_arg);
const char *similar_arg = scc_argparse_find_similar_arg(
ctx->current_cmd, ctx->result.raw_arg);
if (similar_arg != 0) {
scc_printf(lines[ARGPARSE_DID_YOU_MEAN], similar_arg);
}
break;
// FACK ERROR
case SCC_ARGPARSE_ERR_PNT_DEFAULT:
return;
default:
scc_printf("Unknown error: %d\n", err);
break;
}
if (parser->need_help) {
scc_printf(lines[ARGPRASE_USING_HELP_HINT]);
}
if (parser->need_error_add_help) {
scc_argparse_print_help(parser, ctx->current_cmd);
} else if (parser->need_error_add_usage) {
print_usage(parser, ctx->current_cmd);
}
}