feat(argparse): 实现高级命令行参数解析库
- 添加完整的参数解析API,支持子命令、选项和参数定义 - 实现多种数据类型支持:字符串、布尔值、整数、浮点数、枚举等 - 添加约束规范结构体,支持必填项、多值、隐藏选项等功能 - 实现国际化支持,包含中英文错误提示和帮助信息 - 添加模糊匹配功能,当用户输入错误参数时提供相似建议 - 实现详细的帮助信息打印功能,包括使用方法、选项说明等 - 修改底层optparse库,优化选项处理和错误报告机制 - 添加向量类型支持用于管理参数、选项和子命令集合
This commit is contained in:
@@ -1 +1,297 @@
|
||||
#include <argparse.h>
|
||||
#include <argparse.h>
|
||||
|
||||
void scc_argparse_init(scc_argparse_t *parser, const char *program_name,
|
||||
const char *description) {
|
||||
parser->prog_name = program_name;
|
||||
parser->version = "0.1.0";
|
||||
parser->description = description;
|
||||
parser->epilog = null;
|
||||
|
||||
parser->lang = SCC_ARGPARSE_LANG_EN;
|
||||
parser->need_help = true;
|
||||
parser->need_version = true;
|
||||
parser->need_debug = false;
|
||||
scc_argparse_cmd_init(&parser->root_cmd, parser->prog_name,
|
||||
parser->description);
|
||||
}
|
||||
|
||||
scc_argparse_cmd_t *scc_argparse_get_root(scc_argparse_t *parser) {
|
||||
return &parser->root_cmd;
|
||||
}
|
||||
|
||||
void scc_argparse_drop(scc_argparse_t *parser) {
|
||||
scc_argparse_cmd_drop(&parser->root_cmd);
|
||||
}
|
||||
|
||||
static inline scc_argparse_cmd_t *is_subcommand(scc_argparse_cmd_t *cmd,
|
||||
const char *name) {
|
||||
if (!scc_vec_size(cmd->subcmds)) {
|
||||
return null;
|
||||
}
|
||||
scc_vec_foreach(cmd->subcmds, i) {
|
||||
scc_argparse_cmd_t *subcmd = &scc_vec_at(cmd->subcmds, i);
|
||||
if (scc_strcmp(subcmd->name, name) == 0) {
|
||||
return subcmd;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static inline void parse_cmd(scc_optparse_t *optparse,
|
||||
scc_optparse_opt_vec_t *opts,
|
||||
scc_argparse_cmd_t *cmd) {
|
||||
scc_vec_free(*opts);
|
||||
scc_vec_init(*opts);
|
||||
scc_vec_foreach(cmd->opts, i) {
|
||||
scc_argparse_opt_t *opt = &scc_vec_at(cmd->opts, i);
|
||||
int min_args = 0;
|
||||
int max_args = 0;
|
||||
|
||||
// 根据选项类型推断 min_args 和 max_args
|
||||
switch (opt->spec.value_type) {
|
||||
case SCC_ARGPARSE_VAL_TYPE_STRING:
|
||||
case SCC_ARGPARSE_VAL_TYPE_INT:
|
||||
case SCC_ARGPARSE_VAL_TYPE_FLOAT:
|
||||
min_args = 1;
|
||||
max_args = 1;
|
||||
break;
|
||||
case SCC_ARGPARSE_VAL_TYPE_BOOL:
|
||||
min_args = 0;
|
||||
max_args = 0;
|
||||
break;
|
||||
case SCC_ARGPARSE_VAL_TYPE_COUNT:
|
||||
min_args = 0;
|
||||
max_args = 0;
|
||||
break;
|
||||
default:
|
||||
min_args = 0;
|
||||
max_args = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
scc_vec_push(*opts, ((scc_optparse_opt_t){
|
||||
.prefix = '-',
|
||||
.short_name = opt->short_name,
|
||||
.long_name = opt->long_name,
|
||||
.min_args = min_args,
|
||||
.max_args = max_args,
|
||||
.user_data = opt,
|
||||
}));
|
||||
}
|
||||
scc_vec_push(*opts, (scc_optparse_opt_t)SCC_OPTPARSE_OPT_END());
|
||||
scc_optparse_set(optparse, opts->data);
|
||||
}
|
||||
static void push_help(scc_argparse_cmd_t *cmd) {
|
||||
if (cmd == null) {
|
||||
return;
|
||||
}
|
||||
scc_vec_push(cmd->opts, ((scc_argparse_opt_t){
|
||||
.short_name = 'h',
|
||||
.long_name = "help",
|
||||
.description = 0,
|
||||
.spec.value_type = SCC_ARGPARSE_VAL_TYPE_BOOL,
|
||||
}));
|
||||
scc_vec_foreach(cmd->subcmds, i) {
|
||||
push_help(&scc_vec_at(cmd->subcmds, i));
|
||||
}
|
||||
}
|
||||
|
||||
static void init_context(scc_argparse_context_t *ctx, scc_argparse_t *parser,
|
||||
int argc, const char **argv) {
|
||||
ctx->current_cmd = scc_argparse_get_root(parser);
|
||||
if (parser->need_help) {
|
||||
push_help(ctx->current_cmd);
|
||||
}
|
||||
scc_optparse_init(&ctx->optparse, argc, argv);
|
||||
scc_vec_init(ctx->opts);
|
||||
parse_cmd(&ctx->optparse, &ctx->opts, ctx->current_cmd);
|
||||
ctx->positional_index = 0;
|
||||
ctx->parsing_done = false;
|
||||
ctx->lang = parser->lang;
|
||||
}
|
||||
|
||||
static int handle_parse_error(scc_argparse_t *parser,
|
||||
scc_argparse_context_t *ctx) {
|
||||
scc_argparse_err_t error = SCC_ARGPARSE_ERR_NONE;
|
||||
switch (ctx->result.error) {
|
||||
case SCC_OPT_ERROR_NOT_FOUND_SHORT_ARG:
|
||||
case SCC_OPT_ERROR_NOT_FOUND_LONG_ARG:
|
||||
error = SCC_ARGPARSE_ERR_UNKNOWN_ARG;
|
||||
break;
|
||||
case SCC_OPT_ERROR_NOT_ENOUGH_ARGS:
|
||||
error = SCC_ARGPARSE_ERR_MISSING_VALUE;
|
||||
break;
|
||||
case SCC_OPT_ERROR_TOO_MANY_ARGS:
|
||||
error = SCC_ARGPARSE_ERR_INVALID_ARG;
|
||||
break;
|
||||
default:
|
||||
error = SCC_ARGPARSE_ERR_UNKNOWN_ERR;
|
||||
break;
|
||||
}
|
||||
scc_argparse_print_error(ctx, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void validate_and_cleanup(scc_argparse_context_t *ctx,
|
||||
scc_argparse_t *parser) {
|
||||
// 检查必需参数是否都已提供
|
||||
scc_vec_foreach(ctx->current_cmd->args, i) {
|
||||
scc_argparse_arg_t *arg = &scc_vec_at(ctx->current_cmd->args, i);
|
||||
if (arg->spec.flag_required && *arg->spec.store.str_store == NULL) {
|
||||
scc_argparse_print_error(ctx, SCC_ARGPARSE_ERR_MISSING_ARG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 清理资源
|
||||
scc_vec_free(ctx->opts);
|
||||
scc_optparse_drop(&ctx->optparse);
|
||||
}
|
||||
|
||||
static void handle_option(scc_argparse_context_t *ctx, scc_argparse_t *parser) {
|
||||
scc_argparse_opt_t *opt = (scc_argparse_opt_t *)ctx->result.opt->user_data;
|
||||
|
||||
if (parser->need_help && scc_strcmp(opt->long_name, "help") == 0) {
|
||||
scc_argparse_print_help(parser, ctx->current_cmd);
|
||||
ctx->parsing_done = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (opt->spec.flag_store_as_count) {
|
||||
(*opt->spec.store.int_store)++;
|
||||
}
|
||||
|
||||
if (opt->spec.value_type == SCC_ARGPARSE_VAL_TYPE_BOOL) {
|
||||
*opt->spec.store.bool_store = true;
|
||||
}
|
||||
|
||||
if (ctx->result.value) {
|
||||
opt->spec.raw_value = ctx->result.value;
|
||||
*opt->spec.store.str_store = ctx->result.value;
|
||||
}
|
||||
|
||||
// // opt value == null or value != null
|
||||
// scc_argparse_opt_t *org_opt =
|
||||
// (scc_argparse_opt_t *)opt_res.opt->user_data;
|
||||
// if (parser->need_help) {
|
||||
// if (scc_strcmp(org_opt->long_name, "help") == 0) {
|
||||
// scc_argparse_print_help(parser, current_cmd);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (org_opt->spec.store_as_count) {
|
||||
// *org_opt->spec.store.int_store += 1;
|
||||
// }
|
||||
// if (org_opt->spec.value_type == SCC_ARGPARSE_VAL_TYPE_BOOL) {
|
||||
// *org_opt->spec.store.bool_store = true;
|
||||
// }
|
||||
// if (opt_res.value) {
|
||||
// org_opt->spec.raw_value = opt_res.value;
|
||||
// // TODO
|
||||
// *org_opt->spec.store.str_store = opt_res.value;
|
||||
// }
|
||||
}
|
||||
|
||||
static void handle_positional_arg(scc_argparse_context_t *ctx,
|
||||
scc_argparse_t *parser) {
|
||||
scc_argparse_cmd_t *subcmd =
|
||||
is_subcommand(ctx->current_cmd, ctx->result.value);
|
||||
if (subcmd != NULL) {
|
||||
ctx->current_cmd = subcmd;
|
||||
parse_cmd(&ctx->optparse, &ctx->opts, ctx->current_cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->positional_index < scc_vec_size(ctx->current_cmd->args)) {
|
||||
scc_argparse_arg_t *arg =
|
||||
&scc_vec_at(ctx->current_cmd->args, ctx->positional_index);
|
||||
*arg->spec.store.str_store = ctx->result.value;
|
||||
arg->spec.raw_value = ctx->result.value;
|
||||
ctx->positional_index++;
|
||||
} else {
|
||||
scc_argparse_print_error(ctx, SCC_ARGPARSE_ERR_UNKNOWN_ARG);
|
||||
ctx->parsing_done = true;
|
||||
}
|
||||
|
||||
// // position arg
|
||||
// scc_argparse_cmd_t *cmd = is_subcommand(current_cmd,
|
||||
// opt_res.value);
|
||||
|
||||
// if (cmd != null) {
|
||||
// current_cmd = cmd;
|
||||
// parse_cmd(&optparse, &opts, current_cmd);
|
||||
// } else {
|
||||
// // TODO argument
|
||||
// scc_vec_foreach(current_cmd->args, i) {
|
||||
// scc_argparse_arg_t *arg = &scc_vec_at(current_cmd->args,
|
||||
// i); if (*arg->spec.store.str_store == 0) {
|
||||
// *arg->spec.store.str_store = opt_res.value;
|
||||
// arg->spec.raw_value = opt_res.value;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
int scc_argparse_parse(scc_argparse_t *parser, int argc, const char **argv) {
|
||||
scc_argparse_context_t ctx = {0};
|
||||
init_context(&ctx, parser, argc, argv); // 初始化上下文
|
||||
|
||||
while (!ctx.parsing_done &&
|
||||
scc_optparse_parse(&ctx.optparse, &ctx.result)) {
|
||||
if (parser->need_debug) {
|
||||
scc_printf("[%c:%s:%d] %s\n",
|
||||
ctx.result.opt ? ctx.result.opt->short_name : '-',
|
||||
ctx.result.opt ? ctx.result.opt->long_name : "--",
|
||||
ctx.result.error, ctx.result.value);
|
||||
}
|
||||
if (ctx.result.error) {
|
||||
handle_parse_error(parser, &ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ctx.result.opt != null) {
|
||||
handle_option(&ctx, parser);
|
||||
} else if (ctx.result.value != null) {
|
||||
handle_positional_arg(&ctx, parser);
|
||||
} else {
|
||||
UNREACHABLE(); // 不应到达此处
|
||||
}
|
||||
}
|
||||
|
||||
validate_and_cleanup(&ctx, parser);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void scc_argparse_cmd_init(scc_argparse_cmd_t *cmd, const char *name,
|
||||
const char *description) {
|
||||
cmd->name = name ? name : "cmd_name";
|
||||
cmd->description = description ? description : "cmd_description";
|
||||
scc_vec_init(cmd->args);
|
||||
scc_vec_init(cmd->opts);
|
||||
scc_vec_init(cmd->subcmds);
|
||||
}
|
||||
|
||||
void scc_argparse_cmd_drop(scc_argparse_cmd_t *cmd) {
|
||||
scc_vec_free(cmd->args);
|
||||
scc_vec_free(cmd->opts);
|
||||
scc_vec_foreach(cmd->subcmds, i) {
|
||||
scc_argparse_cmd_drop(&scc_vec_at(cmd->subcmds, i));
|
||||
}
|
||||
scc_vec_free(cmd->subcmds);
|
||||
}
|
||||
|
||||
void scc_argparse_cmd_add_arg(scc_argparse_cmd_t *cmd,
|
||||
const scc_argparse_arg_t *arg) {
|
||||
scc_vec_push(cmd->args, *arg);
|
||||
}
|
||||
|
||||
void scc_argparse_cmd_add_opt(scc_argparse_cmd_t *cmd,
|
||||
const scc_argparse_opt_t *opt) {
|
||||
scc_vec_push(cmd->opts, *opt);
|
||||
}
|
||||
|
||||
void scc_argparse_cmd_add_subcmd(scc_argparse_cmd_t *cmd,
|
||||
const scc_argparse_cmd_t *subcmd) {
|
||||
scc_vec_push(cmd->subcmds, *subcmd);
|
||||
}
|
||||
|
||||
221
libs/argparse/src/argparse_print.c
Normal file
221
libs/argparse/src/argparse_print.c
Normal file
@@ -0,0 +1,221 @@
|
||||
#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,
|
||||
|
||||
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",
|
||||
|
||||
[ARGPARSE_UNKNOWN_ARGUMENT] = "Unknown argument '%s'",
|
||||
[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] = "显示帮助信息并退出",
|
||||
|
||||
[ARGPARSE_UNKNOWN_ARGUMENT] = "未知的参数 '%s'",
|
||||
[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;
|
||||
}
|
||||
|
||||
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;
|
||||
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");
|
||||
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[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_err_t err) {
|
||||
const char **lines = (ctx->lang == SCC_ARGPARSE_LANG_ZH) ? fmt_zh : fmt_en;
|
||||
const char *optname = ctx->result.raw_arg;
|
||||
switch (err) {
|
||||
case SCC_ARGPARSE_ERR_INVALID_ARG:
|
||||
case SCC_ARGPARSE_ERR_INVALID_VALUE:
|
||||
scc_printf(lines[ARGPARSE_INVALID_VALUE_FOR_OPTION], optname);
|
||||
break;
|
||||
case SCC_ARGPARSE_ERR_MISSING_ARG:
|
||||
case SCC_ARGPARSE_ERR_MISSING_VALUE:
|
||||
scc_printf(lines[ARGPARSE_OPTION_MISSING_VALUE], optname);
|
||||
break;
|
||||
case SCC_ARGPARSE_ERR_UNKNOWN_ARG:
|
||||
case SCC_ARGPARSE_ERR_UNKNOWN_VALUE:
|
||||
scc_printf(lines[ARGPARSE_UNKNOWN_ARGUMENT], optname);
|
||||
const char *similar_arg =
|
||||
scc_argparse_find_similar_arg(ctx->current_cmd, optname);
|
||||
if (similar_arg != 0) {
|
||||
scc_printf(lines[ARGPARSE_DID_YOU_MEAN], similar_arg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
scc_printf("Unknown error: %d\n", err);
|
||||
}
|
||||
}
|
||||
@@ -145,7 +145,7 @@ int scc_optparse_parse(scc_optparse_t *parser, scc_optparse_result_t *res) {
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
for (const scc_optparse_opt_t *opt = opts; opt->prefix; ++opt) {
|
||||
for (const scc_optparse_opt_t *opt = opts; opt && opt->prefix; ++opt) {
|
||||
if (arg[0] != opt->prefix) {
|
||||
continue;
|
||||
}
|
||||
@@ -216,5 +216,6 @@ RETURN:
|
||||
parser->current.count > res->opt->max_args) {
|
||||
res->error = SCC_OPT_ERROR_TOO_MANY_ARGS;
|
||||
}
|
||||
return res->opt != 0 || res->value != 0;
|
||||
// res->raw_arg = arg;
|
||||
return res->opt != 0 || res->value != 0 || res->error != SCC_OPT_ERROR_NONE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user