diff --git a/src/ArgParse.c b/src/ArgParse.c index 0839806..7367d98 100644 --- a/src/ArgParse.c +++ b/src/ArgParse.c @@ -7,6 +7,10 @@ #include #include +#define RED "\033[0;31m" +#define BLUE "\033[0;34m" +#define RESET "\033[0m" + static bool _AutoHelp = true; // 是否自动添加帮助信息 static bool _COLOR = true; // 是否启用颜色 @@ -37,15 +41,20 @@ ArgParse *argParseInit(char *documentation, ArgParseValueType value_type) { /** * @brief 自动帮助信息回调函数 + * @param argParse ArgParse结构体指针 + * @param val 参数值 + * @param val_len 参数值长度 + * @return 无返回值,将直接结束程序 */ -int __helpCallback(ArgParse *argParse, char **val, int val_len) { +NORETURN int __helpCallback(ArgParse *argParse, char **val, int val_len) { if (argParse == NULL) { - return -1; + exit(1); } char *help_doc = argParseGenerateHelp(argParse); printf("%s\n", help_doc); free(help_doc); - return 0; + argParseFree(argParse); + exit(0); } /** @@ -523,6 +532,7 @@ int __processCommand(ArgParse *argParse, char *name, int command_index) { /** * @brief 解析命令行参数 + * @errors: 错误信息字符串统一又调用方申请,处理函数释放 * @param argParse 解析器指针 * @param argc 参数个数 * @param argv 参数列表 @@ -574,6 +584,47 @@ void argParseParse(ArgParse *argParse, int argc, char *argv[]) { argParse->current_command->val, argParse->current_command->val_len); } + + // 检查全局参数必填参数是否已设置 + for (int i = 0; i < argParse->global_args_len; i++) { + if (argParse->global_args[i]->required && + argParse->global_args[i]->is_trigged == false) { + // 错误处理,必填全局参数未设置 + char *msg = + stringNewCopy(RED "ERROR" RESET ": Global Option " BLUE); + if (argParse->global_args[i]->short_opt != NULL) { + __catStr(&msg, 1, argParse->global_args[i]->short_opt); + } else { + __catStr(&msg, 1, argParse->global_args[i]->long_opt); + } + __catStr(&msg, 1, RESET " is required"); + argParseError(argParse, NULL, msg, + NULL); // 错误处理 + } + } + + // 检查当前命令的必填参数是否已设置 + if (argParse->current_command != NULL) { + for (int i = 0; i < argParse->current_command->args_len; i++) { + if (argParse->current_command->args[i]->required && + argParse->current_command->args[i]->is_trigged == false) { + // 错误处理,必填参数未设置 + char *msg = stringNewCopy(RED "ERROR" RESET ": Command " BLUE); + __catStr(&msg, 1, argParse->current_command->name); + __catStr(&msg, 1, RESET " Option " BLUE); + if (argParse->current_command->args[i]->short_opt != NULL) { + __catStr( + &msg, 1, argParse->current_command->args[i]->short_opt); + } else { + __catStr( + &msg, 1, argParse->current_command->args[i]->long_opt); + } + __catStr(&msg, 1, RESET " is required"); + argParseError( + argParse, argParse->current_command, msg, NULL); // 错误处理 + } + } + } } /** @@ -841,7 +892,6 @@ NORETURN void argParseError(ArgParse *argParse, __catStr(&mgs, 2, "\n", suffix); } - // printf("\033[1;31mERROR\033[0m: Last command is unknown\n"); printf("%s\n", mgs); free(mgs); free(help); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index db66b41..6075c1e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -38,7 +38,11 @@ add_executable(${PROJECT_NAME}val test_val.c) target_link_libraries(${PROJECT_NAME}val CArgParse) add_test(${PROJECT_NAME}val ${PROJECT_NAME}val file1.txt file2.txt file3.txt -v -q) -# 未知命令选项测试,预期打印该命令的帮助信息 +# 必填参数测试 add_executable(${PROJECT_NAME}required test_required.c) target_link_libraries(${PROJECT_NAME}required CArgParse) -add_test(${PROJECT_NAME}required ${PROJECT_NAME}required file1.txt file2.txt file3.txt -v -f d) \ No newline at end of file +add_test(${PROJECT_NAME}required_1 ${PROJECT_NAME}required -f) +add_test(${PROJECT_NAME}required_2 ${PROJECT_NAME}required) +set_tests_properties(${PROJECT_NAME}required_2 PROPERTIES WILL_FAIL TRUE) +add_test(${PROJECT_NAME}required_3 ${PROJECT_NAME}required -h) +add_test(${PROJECT_NAME}required_4 ${PROJECT_NAME}required -f install -h) \ No newline at end of file diff --git a/tests/test_required.c b/tests/test_required.c new file mode 100644 index 0000000..9249791 --- /dev/null +++ b/tests/test_required.c @@ -0,0 +1,144 @@ +#include "ArgParse.h" +#include +#include +#include +#include +#include + +ArgParse *initArgParse() { + ArgParse *argparse = argParseInit("测试程序", ArgParseNOVALUE); + Command *command = NULL; + Command *sub_command = NULL; + + // add global arguments + argParseAddGlobalArg(argparse, + "-v", + "--version", + "Show version", + NULL, + NULL, + false, + ArgParseNOVALUE); + argParseAddGlobalArg(argparse, + "-f", + "--file", + "File name", + NULL, + NULL, + true, + ArgParseNOVALUE); + + // add arguments + command = argParseAddCommand(argparse, + "install", + "Install the package", + NULL, + NULL, + NULL, + ArgParseNOVALUE); + argParseAddArg(command, + "-i", + "--index", + "Index URL", + "https://example.com", + NULL, + false, + ArgParseSINGLEVALUE); + argParseAddArg(command, + "-f", + "--file", + "Package file", + "package.json", + NULL, + true, + ArgParseMULTIVALUE); + argParseAddArg(command, + "-p", + "--package", + "Package file", + "package.json", + NULL, + false, + ArgParseMULTIVALUE); + + sub_command = argParseAddSubCommand(command, + "tools", + "Install tools", + NULL, + NULL, + NULL, + ArgParseMULTIVALUE); + + argParseAddArg(sub_command, + "-t", + "--tool", + "Tool name", + "Tool name", + NULL, + true, + ArgParseMULTIVALUE); + sub_command = argParseAddSubCommand(command, + "tools_sub", + "Install tools", + NULL, + NULL, + NULL, + ArgParseMULTIVALUE); + + argParseAddArg(sub_command, + "-s", + "--source", + "test_source", + "tools subcommand test", + NULL, + true, + ArgParseMULTIVALUE); + + command = argParseAddCommand(argparse, + "uninstall", + "Uninstall the package", + NULL, + NULL, + NULL, + ArgParseSINGLEVALUE); + argParseAddArg(command, + "-p", + "--package", + "Package name", + "Package name", + NULL, + true, + ArgParseMULTIVALUE); + + return argparse; +} + +int main(int argc, char *argv[]) { + ArgParse *argparse = initArgParse(); + + argParseParse(argparse, argc, argv); + + char *val = argParseGetVal(argparse); + if (val) { + printf("val: %s\n", val); + } + + // int len = 0; + // char **vals = argParseGetValList(argparse, &len); + + // char *test_val[3] = {"file1.txt", "file2.txt", "file3.txt"}; + + // if (vals) { + // for (int i = 0; i < len; i++) { + // printf("vals: %s\n", vals[i]); + // assert(strcmp(vals[i], test_val[i]) == 0); + // } + // } + + // assert(argParseCheckGlobalTriggered(argparse, "-v")); + // assert(argParseCheckGlobalTriggered(argparse, "-f")); + + argParseFree(argparse); + + return 0; +} \ No newline at end of file