1 Star 0 Fork 0

mirror_repo/cmdparser

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
cmdparser.c 25.56 KB
一键复制 编辑 原始数据 按行查看 历史
XUJINKAI 提交于 2022-11-12 10:48 +08:00 . Apache License 2.0
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
/*
Copyright 2022 github.com/XUJINKAI/cmdparser. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
*/
#include "cmdparser.h"
#include <stdlib.h>
#include <string.h>
// isatty
#if defined(__GLIBC__)
#include <unistd.h>
#endif
#if defined(_MSC_VER)
#include <io.h>
#define isatty _isatty
#define fileno _fileno
#endif
// ============================================================================
// utils
// ============================================================================
#define HAS_FLAG(VAR, FLAG) (((VAR) & (FLAG)) == (FLAG))
static bool is_all_zero(void *__p, size_t __l)
{
char *pt = (char *)__p;
while (__l--)
{
if (*pt++)
{
return false;
}
}
return true;
}
static int nonzero_countof(void *array, int element_size)
{
if (array == NULL)
return 0;
int count = 0;
char *pt = (char *)array;
while (!is_all_zero(pt, element_size))
{
pt += element_size;
count++;
}
return count;
}
// ============================================================================
// default methods
// ============================================================================
#define HELP_PREFIX_LEN 29
#define IS_INPUTABLE_KEY(CH) \
((((CH) >= 'a') && ((CH) <= 'z')) || (((CH) >= 'A') && ((CH) <= 'Z')) || (((CH) >= '0') && ((CH) <= '9')))
static void default_error_parse_handler(cmdp_error_params_st *params)
{
switch (params->type)
{
case CMDP_ERROR_UNKNOWN_COMMAND:
fprintf(params->err_stream, "Unknown command %s.\n", params->s);
break;
case CMDP_ERROR_UNKNOWN_OPTION:
if (params->c)
{
fprintf(params->err_stream, "Unknown option -%c.\n", params->c);
}
if (params->s)
{
fprintf(params->err_stream, "Unknown option --%s.\n", params->s);
}
break;
case CMDP_ERROR_MISSING_OPTION_ARG:
if (params->c)
{
fprintf(params->err_stream, "Option -%c require args.\n", params->c);
}
if (params->s)
{
fprintf(params->err_stream, "Option --%s require args.\n", params->s);
}
break;
case CMDP_ERROR_PARSE_INT:
fprintf(params->err_stream, "Parse int failed: %s.\n", params->s);
break;
case CMDP_ERROR_PARSE_DOUBLE:
fprintf(params->err_stream, "Parse float failed: %s.\n", params->s);
break;
case CMDP_ERROR_REPEAT_OPTION:
if (params->c)
{
fprintf(params->err_stream, "Option -%c repeat.\n", params->c);
}
if (params->s)
{
fprintf(params->err_stream, "Option --%s repeat.\n", params->s);
}
break;
default:
break;
}
}
static void default_doc_gen_options_handler(FILE *fp, cmdp_option_st *options)
{
/*
\s\s[command]\s{29-2-len}doc\n
-h, --help Give this help list
*/
cmdp_option_st *n = options;
int count = nonzero_countof(options, sizeof(cmdp_option_st));
for (int i = 0; i < count; i++, n++)
{
if (n->fn_flag)
{
cmdp_flag_t flag = n->fn_flag();
if (HAS_FLAG(flag, CMDP_FLAG_HIDE) || HAS_FLAG(flag, CMDP_FLAG_DISABLE))
{
continue;
}
}
if (n->short_option == 0 && n->long_option == NULL)
{
fprintf(fp, "%s", n->description);
continue;
}
fprintf(fp, " ");
int pos = 2;
if (IS_INPUTABLE_KEY(n->short_option))
{
fprintf(fp, "%c%c", '-', n->short_option);
pos += 2;
if (n->long_option != NULL)
{
fprintf(fp, ", ");
pos += 2;
}
}
#if CMDP_DOC_ALIGN_LONG_OPTION
else
{
fprintf(fp, " ");
pos += 4;
}
#endif
if (n->long_option != NULL)
{
fprintf(fp, "%s%s", "--", n->long_option);
pos += 2 + strlen(n->long_option);
}
char *alias = n->type_name;
if (alias == NULL)
{
switch (n->type)
{
case CMDP_TYPE_STRING_PTR:
alias = (char *)"<string>";
break;
case CMDP_TYPE_INT4:
alias = (char *)"<int>";
break;
case CMDP_TYPE_DOUBLE:
alias = (char *)"<number>";
break;
case CMDP_TYPE_NONE:
case CMDP_TYPE_BOOL:
break;
}
}
if (alias != NULL)
{
fprintf(fp, "%s%s", " ", alias);
pos += 1 + strlen(alias);
}
long remain_prefix = HELP_PREFIX_LEN - pos;
if (remain_prefix >= 2)
{
while (remain_prefix--)
{
fputc(' ', fp);
}
}
else
{
fprintf(fp, "\n ");
}
fprintf(fp, "%s\n", n->description);
}
}
static void default_doc_gen_command_handler(FILE *fp, cmdp_command_st *command)
{
if (command->doc)
{
fputs(command->doc, fp);
}
if (command->sub_commands != NULL)
{
int sub_command_count = nonzero_countof(command->sub_commands, sizeof(cmdp_command_st *));
for (int i = 0; i < sub_command_count; i++)
{
cmdp_command_st *n = command->sub_commands[i];
if (n->fn_flag)
{
cmdp_flag_t flag = n->fn_flag();
if (HAS_FLAG(flag, CMDP_FLAG_HIDE) || HAS_FLAG(flag, CMDP_FLAG_DISABLE))
{
continue;
}
}
if (n->name == NULL)
{
if (n->desc)
{
fputs(n->desc, fp);
}
if (n->doc)
{
fputs(n->doc, fp);
}
}
else
{
fprintf(fp, " ");
int pos = 2;
if (n->alias_name != NULL)
{
fprintf(fp, "%s, ", n->alias_name);
pos += strlen(n->alias_name) + 2;
}
fprintf(fp, "%s", n->name);
pos += strlen(n->name);
long remain_prefix = HELP_PREFIX_LEN - pos;
while (remain_prefix--)
{
fputc(' ', fp);
}
fprintf(fp, "%s\n", n->desc);
}
n++;
}
}
if (command->options != NULL)
{
cmdp_fprint_options_doc(fp, command->options);
}
if (command->doc_tail)
{
fputs(command->doc_tail, fp);
}
}
// ============================================================================
// main logic
// ============================================================================
static void cmdp_fprint_all_documents_recursive(FILE *fp, cmdp_command_st *cmdp, char *command_name, bool colored)
{
#define GREEN(STRING) "\x1b[32m" STRING "\x1b[0m"
#define CYAN(STRING) "\x1b[36m" STRING "\x1b[0m"
fprintf(fp, (colored ? CYAN(">>") " " GREEN("%s") "\n" : ">> %s\n"), command_name);
cmdp_fprint_command_doc(fp, cmdp);
int count = nonzero_countof(cmdp->sub_commands, sizeof(cmdp_command_st *));
for (int i = 0; i < count; i++)
{
cmdp_command_st *p = cmdp->sub_commands[i];
if (p->fn_flag)
{
cmdp_flag_t flag = p->fn_flag();
if (HAS_FLAG(flag, CMDP_FLAG_HIDE) || HAS_FLAG(flag, CMDP_FLAG_DISABLE))
{
continue;
}
}
if (p->name == NULL)
{
continue;
}
size_t cmd_name_len = strlen(command_name) + strlen(p->name) + 2;
char *cmd_name = (char *)malloc(cmd_name_len);
memset(cmd_name, 0, cmd_name_len);
snprintf(cmd_name, cmd_name_len, "%s %s", command_name, p->name);
fprintf(fp, "\n");
cmdp_fprint_all_documents_recursive(fp, p, cmd_name, colored);
free(cmd_name);
}
}
static cmdp_option_st *find_option(int short_option, char *long_option, cmdp_command_st *cmdp)
{
int count = nonzero_countof(cmdp->options, sizeof(cmdp_option_st));
for (int i = 0; i < count; i++)
{
cmdp_option_st *p = cmdp->options + i;
if ((short_option != 0 && p->short_option != 0 && p->short_option == short_option) ||
(long_option != NULL && p->long_option != NULL && strcmp(p->long_option, long_option) == 0))
{
if (p->fn_flag && HAS_FLAG(p->fn_flag(), CMDP_FLAG_DISABLE))
{
return NULL;
}
return p;
}
}
if (cmdp->__parent)
{
return find_option(short_option, long_option, cmdp->__parent);
}
return NULL;
}
static cmdp_command_st *find_command(char *command_name, cmdp_command_st **commands, int count)
{
for (int i = 0; i < count; i++)
{
cmdp_command_st *p = commands[i];
bool match_name = p->name != NULL && strcmp(command_name, p->name) == 0;
bool match_alias = p->alias_name != NULL && (strcmp(command_name, p->alias_name) == 0);
bool match_variant = false;
if (p->variant_cmds != NULL)
{
int variant_count = nonzero_countof(p->variant_cmds, sizeof(char *));
for (int j = 0; j < variant_count; j++)
{
if (strcmp(command_name, p->variant_cmds[j]) == 0)
{
match_variant = true;
break;
}
}
}
if (match_name || match_alias || match_variant)
{
if (p->fn_flag && HAS_FLAG(p->fn_flag(), CMDP_FLAG_DISABLE))
{
return NULL;
}
return p;
}
}
return NULL;
}
#define _EC_ERROR_MASK_ 0x100
typedef enum
{
EVAL_CODE_DONE,
EVAL_CODE_ARG_USED,
EVAL_CODE_ERROR_ARG_NULL = _EC_ERROR_MASK_,
EVAL_CODE_ERROR_PARSE_INT,
EVAL_CODE_ERROR_PARSE_FLOAT,
EVAL_CODE_ERROR_REPEAT_OPTION,
} EVAL_CODE;
static EVAL_CODE eval_option_output(cmdp_option_st *option, char *arg)
{
if (HAS_FLAG(option->__flag, __CMDP_OPT_IS_PARSED))
{
return EVAL_CODE_ERROR_REPEAT_OPTION;
}
switch (option->type)
{
case CMDP_TYPE_BOOL: {
if (option->output_ptr != NULL)
{
*(bool *)option->output_ptr = true;
}
return EVAL_CODE_DONE;
}
case CMDP_TYPE_INT4: {
if (arg == NULL)
{
return EVAL_CODE_ERROR_ARG_NULL;
}
char *endl = NULL;
long l = strtol(arg, &endl, 10);
if (endl == arg || *endl != '\0')
{
return EVAL_CODE_ERROR_PARSE_INT;
}
if (option->output_ptr != NULL)
{
*(int *)option->output_ptr = l;
}
return EVAL_CODE_ARG_USED;
}
case CMDP_TYPE_DOUBLE: {
if (arg == NULL)
{
return EVAL_CODE_ERROR_ARG_NULL;
}
char *endd = NULL;
double d = strtod(arg, &endd);
if (endd == arg || *endd != '\0')
{
return EVAL_CODE_ERROR_PARSE_FLOAT;
}
if (option->output_ptr != NULL)
{
*(double *)option->output_ptr = d;
}
return EVAL_CODE_ARG_USED;
}
case CMDP_TYPE_STRING_PTR: {
if (arg == NULL)
{
return EVAL_CODE_ERROR_ARG_NULL;
}
if (option->output_ptr != NULL)
{
*(char **)option->output_ptr = arg;
}
return EVAL_CODE_ARG_USED;
}
case CMDP_TYPE_NONE:
default:
return EVAL_CODE_DONE;
}
return EVAL_CODE_DONE;
}
#define _parse_ret_0 (-1)
#define _parse_ret_1 (-2)
static int cmdp_parse_args(int argc, char **argv, cmdp_command_st *cmdp, cmdp_ctx *ctx, int recursive)
{
cmdp_error_params_st error_params = {
.err_stream = ctx->err_stream,
.cmdp = cmdp,
};
#define __ERROR_HANDLER(_type, _c, _s) \
do \
{ \
error_params.type = _type; \
error_params.c = _c; \
error_params.s = _s; \
ctx->fn_error_parse(&error_params); \
} while (0)
int parsed_options = 0;
int arg_index = 0;
for (; arg_index < argc; arg_index++)
{
char *cur_arg = argv[arg_index];
char *next_arg = (arg_index + 1) < argc ? argv[arg_index + 1] : NULL;
int cur_len = strlen(cur_arg);
// -short
if (cur_len >= 2 && cur_arg[0] == '-' && cur_arg[1] != '-')
{
EVAL_CODE eval_code = EVAL_CODE_DONE;
char *eval_arg = NULL;
char cur_ch = '\0';
for (int ch_idx = 1; ch_idx < cur_len; ch_idx++)
{
// e.g. -anop <NAME>. loop char by char
cur_ch = cur_arg[ch_idx];
if (ctx->help_short_option != '\0' && cur_ch == ctx->help_short_option)
{
ctx->fn_doc_gen_command(ctx->out_stream, cmdp);
return _parse_ret_0;
}
cmdp_option_st *find = find_option(cur_ch, 0, cmdp);
if (find == NULL)
{
__ERROR_HANDLER(CMDP_ERROR_UNKNOWN_OPTION, cur_ch, NULL);
return _parse_ret_1;
}
eval_arg = (eval_code == EVAL_CODE_ARG_USED) ? NULL : next_arg;
eval_code = eval_option_output(find, eval_arg);
find->__flag |= __CMDP_OPT_IS_PARSED;
if (HAS_FLAG(eval_code, _EC_ERROR_MASK_))
{
break;
}
}
switch (eval_code)
{
case EVAL_CODE_ARG_USED:
arg_index++;
break;
case EVAL_CODE_ERROR_ARG_NULL:
__ERROR_HANDLER(CMDP_ERROR_MISSING_OPTION_ARG, cur_ch, NULL);
return _parse_ret_1;
case EVAL_CODE_ERROR_PARSE_INT:
__ERROR_HANDLER(CMDP_ERROR_PARSE_INT, 0, eval_arg);
return _parse_ret_1;
case EVAL_CODE_ERROR_PARSE_FLOAT:
__ERROR_HANDLER(CMDP_ERROR_PARSE_DOUBLE, 0, eval_arg);
return _parse_ret_1;
case EVAL_CODE_ERROR_REPEAT_OPTION:
__ERROR_HANDLER(CMDP_ERROR_REPEAT_OPTION, cur_ch, NULL);
return _parse_ret_1;
case EVAL_CODE_DONE:
break;
}
parsed_options += 1;
}
// --long
else if (cur_len >= 3 && cur_arg[0] == '-' && cur_arg[1] == '-')
{
/*
--path=<PATH> eq_ptr=long_option_start+n
--path <PATH> eq_ptr=NULL, next_arg=<PATH>
*/
char *long_option_start = cur_arg + 2;
char *eq_ptr = strchr(long_option_start, '=');
int long_len_calc = (eq_ptr == NULL) ? (int)strlen(long_option_start) : (eq_ptr - long_option_start);
char long_option_real[128] = {0};
strncpy(long_option_real, long_option_start, long_len_calc);
if (ctx->help_long_option != NULL && strcmp(ctx->help_long_option, long_option_start) == 0)
{
ctx->fn_doc_gen_command(ctx->out_stream, cmdp);
return _parse_ret_0;
}
cmdp_option_st *find = find_option(0, long_option_real, cmdp);
if (find == NULL)
{
__ERROR_HANDLER(CMDP_ERROR_UNKNOWN_OPTION, 0, long_option_real);
return _parse_ret_1;
}
char *eval_arg = (eq_ptr == NULL) ? next_arg : eq_ptr + 1;
EVAL_CODE eval_code = eval_option_output(find, eval_arg);
find->__flag |= __CMDP_OPT_IS_PARSED;
switch (eval_code)
{
case EVAL_CODE_ARG_USED:
if (eq_ptr == NULL)
{
arg_index++;
}
break;
case EVAL_CODE_ERROR_ARG_NULL:
__ERROR_HANDLER(CMDP_ERROR_MISSING_OPTION_ARG, 0, long_option_real);
return _parse_ret_1;
case EVAL_CODE_ERROR_PARSE_INT:
__ERROR_HANDLER(CMDP_ERROR_PARSE_INT, 0, eval_arg);
return _parse_ret_1;
case EVAL_CODE_ERROR_PARSE_FLOAT:
__ERROR_HANDLER(CMDP_ERROR_PARSE_DOUBLE, 0, eval_arg);
return _parse_ret_1;
case EVAL_CODE_ERROR_REPEAT_OPTION:
__ERROR_HANDLER(CMDP_ERROR_REPEAT_OPTION, 0, long_option_real);
return _parse_ret_1;
case EVAL_CODE_DONE:
break;
}
parsed_options += 1;
}
// -- (end of options)
else if (cur_len == 2 && cur_arg[0] == '-' && cur_arg[1] == '-')
{
arg_index += 1;
break;
}
else
{
// not option, break
break;
}
}
if (cmdp->sub_commands && arg_index < argc)
{
int commands_count = nonzero_countof(cmdp->sub_commands, sizeof(cmdp_command_st *));
cmdp_command_st *find = find_command(argv[arg_index], cmdp->sub_commands, commands_count);
if (find == NULL)
{
#if CMDP_PARSE_UNKNOWN_COMMAND_AS_ARG
return arg_index;
#else
__ERROR_HANDLER(CMDP_ERROR_UNKNOWN_COMMAND, 0, argv[arg_index]);
return _parse_ret_1;
#endif
}
find->__flag = __CMDP_CMD_IS_PARSED;
find->__call_name = argv[arg_index];
int next_parsed = cmdp_parse_args(argc - arg_index - 1, argv + arg_index + 1, find, ctx, recursive + 1);
if (next_parsed < 0)
{
return next_parsed;
}
return 1 + arg_index + next_parsed;
}
return arg_index;
}
static int cmdp_count_parsed_options(cmdp_command_st *cmdp)
{
if (cmdp->options == NULL)
{
return 0;
}
int count = 0;
int options_count = nonzero_countof(cmdp->options, sizeof(cmdp_option_st));
for (int i = 0; i < options_count; i++)
{
cmdp_option_st *opt = cmdp->options + i;
if (HAS_FLAG(opt->__flag, __CMDP_OPT_IS_PARSED))
{
count++;
}
}
return count;
}
static cmdp_command_st *cmdp_find_parsed_cmd(cmdp_command_st *cmdp)
{
if (cmdp->sub_commands == NULL)
{
return NULL;
}
int commands_count = nonzero_countof(cmdp->sub_commands, sizeof(cmdp_command_st *));
for (int i = 0; i < commands_count; i++)
{
cmdp_command_st *sub_cmd = cmdp->sub_commands[i];
if (HAS_FLAG(sub_cmd->__flag, __CMDP_CMD_IS_PARSED))
{
return sub_cmd;
}
}
return NULL;
}
static int cmdp_run_callback(int argc, char **argv, cmdp_command_st *cmdp, cmdp_ctx *ctx, int recursive)
{
cmdp_command_st *sub_cmd = cmdp_find_parsed_cmd(cmdp);
int parsed_options = cmdp_count_parsed_options(cmdp);
if (cmdp->fn_process == NULL && sub_cmd == NULL && parsed_options == 0 && argc == 0)
{
ctx->fn_doc_gen_command(ctx->out_stream, cmdp);
return 0;
}
if (cmdp->fn_process != NULL)
{
cmdp_process_param_st fn_process_param = {
.argc = argc,
.argv = argv,
.call_name = cmdp->__call_name,
.current = cmdp,
.next = sub_cmd,
.opts = parsed_options,
.sub_level = recursive,
.out_stream = ctx->out_stream,
.err_stream = ctx->err_stream,
.error_code = 1,
};
cmdp_action_t code = cmdp->fn_process(&fn_process_param);
bool show_help = HAS_FLAG(code, CMDP_ACT_SHOW_HELP);
switch (code & 0xFFFF)
{
case CMDP_ACT_OK:
if (show_help)
{
ctx->fn_doc_gen_command(ctx->out_stream, cmdp);
}
return 0;
case CMDP_ACT_ERROR:
if (show_help)
{
ctx->fn_doc_gen_command(ctx->err_stream, cmdp);
}
return fn_process_param.error_code;
case CMDP_ACT_CONTINUE:
default:
if (show_help)
{
ctx->fn_doc_gen_command(ctx->out_stream, cmdp);
}
}
}
if (sub_cmd != NULL)
{
return cmdp_run_callback(argc, argv, sub_cmd, ctx, recursive + 1);
}
return 0;
}
static void cmdp_setup_option_output(cmdp_option_st *option)
{
if (option->output_ptr == NULL)
{
return;
}
switch (option->type)
{
case CMDP_TYPE_BOOL:
*(bool *)option->output_ptr = false;
break;
case CMDP_TYPE_INT4:
*(int *)option->output_ptr = 0;
break;
case CMDP_TYPE_DOUBLE:
*(double *)option->output_ptr = 0;
break;
case CMDP_TYPE_STRING_PTR:
*(char **)option->output_ptr = NULL;
break;
default:
break;
}
}
static void cmdp_setup(cmdp_command_st *cmdp, cmdp_command_st *parent)
{
cmdp->__parent = parent;
cmdp->__flag = 0;
cmdp->__call_name = NULL;
if (cmdp->sub_commands)
{
int commands_count = nonzero_countof(cmdp->sub_commands, sizeof(cmdp_command_st *));
for (int i = 0; i < commands_count; i++)
{
cmdp_setup(cmdp->sub_commands[i], cmdp);
}
}
if (cmdp->options)
{
int options_count = nonzero_countof(cmdp->options, sizeof(cmdp_option_st));
for (int i = 0; i < options_count; i++)
{
cmdp_option_st *opt = cmdp->options + i;
opt->__flag = 0;
cmdp_setup_option_output(opt);
}
}
}
// ============================================================================
// expose
// ============================================================================
cmdp_flag_t cmdp_flag_always_hide()
{
return CMDP_FLAG_HIDE;
}
int cmdp_run(int argc, char **argv, cmdp_command_st *root_command, cmdp_ctx *ctx)
{
if (ctx)
{
cmdp_complete_context(ctx);
}
else
{
cmdp_ctx default_ctx = {0};
cmdp_set_default_context(&default_ctx);
ctx = &default_ctx;
}
cmdp_setup(root_command, NULL);
int parsed = cmdp_parse_args(argc, argv, root_command, ctx, 0);
if (parsed < 0)
{
/*
-1: return 0
-2: return 1
*/
return -parsed - 1;
}
return cmdp_run_callback(argc - parsed, argv + parsed, root_command, ctx, 0);
}
void cmdp_fprint_options_doc(FILE *fp, cmdp_option_st *options)
{
default_doc_gen_options_handler(fp, options);
}
void cmdp_fprint_command_doc(FILE *fp, cmdp_command_st *command)
{
default_doc_gen_command_handler(fp, command);
}
void cmdp_fprint_all_documents(FILE *fp, cmdp_command_st *command)
{
char *cmd_name = command->name ? command->name : (char *)"";
bool fp_istty = isatty(fileno(fp));
cmdp_fprint_all_documents_recursive(fp, command, cmd_name, fp_istty);
}
void cmdp_help(cmdp_command_st *command)
{
cmdp_fprint_command_doc(stdout, command);
}
void cmdp_set_default_context(cmdp_ctx *ctx)
{
if (ctx == NULL)
{
return;
}
ctx->help_short_option = 'h';
ctx->help_long_option = (char *)"help";
ctx->fn_doc_gen_command = default_doc_gen_command_handler;
ctx->fn_doc_gen_options = default_doc_gen_options_handler;
ctx->fn_error_parse = default_error_parse_handler;
ctx->out_stream = stdout;
ctx->err_stream = stderr;
}
void cmdp_complete_context(cmdp_ctx *ctx)
{
if (ctx == NULL)
{
return;
}
if (ctx->fn_doc_gen_command == NULL)
{
ctx->fn_doc_gen_command = default_doc_gen_command_handler;
}
if (ctx->fn_doc_gen_options == NULL)
{
ctx->fn_doc_gen_options = default_doc_gen_options_handler;
}
if (ctx->fn_error_parse == NULL)
{
ctx->fn_error_parse = default_error_parse_handler;
}
if (ctx->out_stream == NULL)
{
ctx->out_stream = stdout;
}
if (ctx->err_stream == NULL)
{
ctx->err_stream = stderr;
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/mirror_repo/cmdparser.git
git@gitee.com:mirror_repo/cmdparser.git
mirror_repo
cmdparser
cmdparser
master

搜索帮助