Compare commits
	
		
			8 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b4663a01e8 | |||
| b1eaae793e | |||
| ce4d0fc423 | |||
| f6ee49f85e | |||
| 924f9662b5 | |||
| 5df2e31973 | |||
| c71c9b6d15 | |||
| 3ade1fd1aa | 
							
								
								
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| MIT License | ||||
|  | ||||
| Copyright (c) 2025 youmetme | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										181
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										181
									
								
								README.md
									
									
									
									
									
								
							| @@ -5,8 +5,13 @@ C语言易用的命令参数分析 | ||||
|  | ||||
| # 特性 | ||||
| - 自动生成帮助信息 | ||||
| - 命令自动帮助信息 | ||||
| - 默认值支持 | ||||
| - 子命令支持 | ||||
| - 命令参数支持 | ||||
| - 全局参数 | ||||
| - 互斥参数(即将) | ||||
|  | ||||
|  | ||||
|  | ||||
| # 安装 | ||||
| @@ -78,3 +83,179 @@ int main(int argc, char *argv[]) { | ||||
| example -h | ||||
| ``` | ||||
|  | ||||
|  | ||||
|  | ||||
| # API | ||||
| 该API将分为两类,一类是用于构造解析器,另一类将用于解析参数 | ||||
|  | ||||
| ## 构造解析器 | ||||
|  | ||||
| 1. 初始化解析器 | ||||
| ```c | ||||
| ArgParse *argParseInit(char *documentation,ArgParseValueType value_type); | ||||
| ``` | ||||
| - `documentation` 解析器的文档信息 | ||||
| - `valueType` 程序本身需要的值类型 | ||||
|  | ||||
| 2. 添加命令 | ||||
| ```c | ||||
| Command *argParseAddCommand(ArgParse         *argParse, | ||||
|                             char             *name, | ||||
|                             char             *help, | ||||
|                             char             *default_val,  | ||||
|                             ArgParseCallback  callback, | ||||
|                             CommandGroup     *group, | ||||
|                             ArgParseValueType value_type); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| - `name` 命令名称 | ||||
| - `help` 命令帮助信息 | ||||
| - `defaultVal` 默认值 | ||||
| - `callback` 命令回调函数(可选) | ||||
| - `group` 命令组(可选) | ||||
| - `valueType` 命令参数类型 | ||||
|  | ||||
| 3. 添加命令参数 | ||||
| ```c | ||||
| CommandArgs *argParseAddArg(Command          *command, | ||||
|                             char             *short_opt, | ||||
|                             char             *long_opt, | ||||
|                             char             *help, | ||||
|                             char             *default_val, | ||||
|                             ArgParseCallback  callback, | ||||
|                             bool              required, | ||||
|                             ArgParseValueType value_type); | ||||
| ``` | ||||
| - `command` 命令 | ||||
| - `shortOpt` 短选项 | ||||
| - `longOpt` 长选项 | ||||
| - `help` 帮助信息 | ||||
| - `defaultVal` 默认值 | ||||
| - `callback` 回调函数(可选) | ||||
| - `required` 是否必须 | ||||
| - `valueType` 参数类型 | ||||
|  | ||||
| 4. 添加子命令 | ||||
| ```c | ||||
| Command *argParseAddSubCommand(Command          *Parent, | ||||
|                                char             *name, | ||||
|                                char             *help, | ||||
|                                char             *default_val, | ||||
|                                ArgParseCallback  callback, | ||||
|                                CommandGroup     *group, | ||||
|                                ArgParseValueType value_type); | ||||
| ``` | ||||
| - `Parent` 父命令 | ||||
| - `name` 命令名称 | ||||
| - `help` 命令帮助信息 | ||||
| - `defaultVal` 默认值 | ||||
| - `callback` 回调函数(可选) | ||||
| - `group` 命令组(可选) | ||||
| - `valueType` 命令参数类型 | ||||
|  | ||||
| 5. 添加全局参数 | ||||
| ```c | ||||
| CommandArgs *argParseAddGlobalArg(ArgParse         *argParse, | ||||
|                                   char             *short_opt, | ||||
|                                   char             *long_opt, | ||||
|                                   char             *help, | ||||
|                                   char             *default_val, | ||||
|                                   ArgParseCallback  callback, | ||||
|                                   bool              required, | ||||
|                                   ArgParseValueType value_type); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| - `shortOpt` 短选项 | ||||
| - `longOpt` 长选项 | ||||
| - `help` 帮助信息 | ||||
| - `defaultVal` 默认值 | ||||
| - `callback` 回调函数(可选) | ||||
| - `required` 是否必须 | ||||
| - `valueType` 参数类型 | ||||
|  | ||||
| ## 解析参数API | ||||
| 1. 解析参数 | ||||
| ```c | ||||
| void argParseParse(ArgParse *argParse, int argc, char *argv[]); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| - `argc` 参数个数 | ||||
| - `argv` 参数列表 | ||||
|  | ||||
| 2. 获取当前解析到的命令名字 | ||||
| ```c | ||||
| char *argParseGetCurCommandName(ArgParse *argParse); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| > 注意,解析到的命令为最后一次出现的命令,也可能是子命令 | ||||
|  | ||||
|  | ||||
| 3. 获取当前命令的值 | ||||
| ```c | ||||
| char *argParseGetCurCommandValue(ArgParse *argParse); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| > 注意,解析到的命令为最后一次出现的命令,也可能是子命令 | ||||
|  | ||||
| 4. 获取当前命令的某个参数的值 | ||||
| ```c | ||||
| char *argParseGetCurArg(ArgParse *argParse, char *opt); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| - `opt` 参数选项 | ||||
|  | ||||
| 5. 获取当前命令的某个选项的值列表(当为多值类型时使用该函数) | ||||
| ```c | ||||
| char **argParseGetCurArgList(ArgParse *argParse, char *opt, int *len); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| - `opt` 参数选项 | ||||
| - `len` 参数个数 | ||||
|  | ||||
| 6. 获取全局选项的值 | ||||
| ```c | ||||
| char *argParseGetGlobalArg(ArgParse *argParse, char *opt); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| - `opt` 参数选项 | ||||
|  | ||||
| 7. 获取全局选项的值列表 | ||||
| ```c | ||||
| char **argParseGetGlobalArgList(ArgParse *argParse, char *opt, int *len); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| - `opt` 参数选项 | ||||
| - `len` 参数个数 | ||||
|  | ||||
| 8. 获取程序值 | ||||
| 该值为非命令的值,类似`gcc main.c`,该类程序没有使用命令,因此该值就是`main.c` | ||||
| ```c | ||||
| char  *argParseGetVal(ArgParse *argParse); | ||||
| char **argParseGetValList(ArgParse *argParse, int *len); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| - `len` 参数个数 | ||||
|  | ||||
|  | ||||
| ### 触发检测API | ||||
| 1. 检测当前检测的命令的某个选项是否触发 | ||||
| ```c | ||||
| bool argParseCheckCurArgTriggered(ArgParse *argParse, char *opt); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| - `opt` 参数选项 | ||||
|  | ||||
|  | ||||
| 2. 检测某个命令是否被触发 | ||||
| ```c | ||||
| bool argParseCheckCommandTriggered(ArgParse *argParse, char *command_name); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| - `command_name` 命令名称 | ||||
|  | ||||
| 3. 检测某个全局选项是否被触发 | ||||
| ```c | ||||
| bool argParseCheckGlobalTriggered(ArgParse *argParse, char *opt); | ||||
| ``` | ||||
| - `argParse` 解析器 | ||||
| - `opt` 参数选项 | ||||
| @@ -6,7 +6,7 @@ import os | ||||
|  | ||||
| class loggingRecipe(ConanFile): | ||||
|     name = "cargparse" | ||||
|     version = "0.2.0" | ||||
|     version = "0.3.0" | ||||
|     license = "MIT" | ||||
|     author = "321640253@qq.com" | ||||
|     url = "https://gitea.youmetme.wang/youmetme/logging" | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
| #include <string.h> | ||||
|  | ||||
| ArgParse *Init() { | ||||
|     ArgParse *ap = argParseInit("简单的命令行工具示例"); | ||||
|     ArgParse *ap = argParseInit("简单的命令行工具示例",NOVALUE); | ||||
|  | ||||
|     // 添加第一个命令 | ||||
|     Command *cmd = argParseAddCommand( | ||||
|   | ||||
| @@ -69,8 +69,12 @@ typedef struct ArgParse { | ||||
|     struct CommandArgs **global_args;     // 全局参数 | ||||
|     int                  global_args_len; // 全局参数个数 | ||||
|     char                *documentation;   // 帮助文档 | ||||
|     ArgParseValueType value_type; // 值类型 程序默认需要的值例如 gcc main.c | ||||
|  | ||||
|     /* 解析所用到的属性*/ | ||||
|     struct Command *current_command; // 当前解析到的命令 | ||||
|     char          **val; | ||||
|     int             val_len; | ||||
|     int             argc; // 参数个数 | ||||
|     char          **argv; // 参数列表 | ||||
| } ArgParse; | ||||
| @@ -79,9 +83,11 @@ typedef struct ArgParse { | ||||
|  | ||||
| /** | ||||
|  * @brief 初始化解析器 | ||||
|  * @param documentation 帮助文档 | ||||
|  * @param value_type 值类型,程序默认需要的值例如 gcc main.c | ||||
|  * @return ArgParse* 解析器指针 | ||||
|  */ | ||||
| ArgParse *argParseInit(char *documentation); | ||||
| ArgParse *argParseInit(char *documentation, ArgParseValueType value_type); | ||||
|  | ||||
| /** | ||||
|  * @brief 释放解析器 | ||||
| @@ -268,6 +274,9 @@ bool argParseCheckCommandTriggered(ArgParse *argParse, char *command_name); | ||||
|  */ | ||||
| bool argParseCheckGlobalTriggered(ArgParse *argParse, char *opt); | ||||
|  | ||||
| char  *argParseGetVal(ArgParse *argParse); | ||||
| char **argParseGetValList(ArgParse *argParse, int *len); | ||||
|  | ||||
| /** End----------------解析API---------------- */ | ||||
|  | ||||
| /** | ||||
| @@ -296,8 +305,8 @@ argParseGenerateArgErrorMsg(ArgParse *argParse, char *name, bool short_flag); | ||||
|  | ||||
| _Noreturn void argParseError(ArgParse   *argParse, | ||||
|                              Command    *lastCommand, | ||||
|                              char     *prefix, | ||||
|                              char     *suffix); | ||||
|                              const char *prefix, | ||||
|                              const char *suffix); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|   | ||||
							
								
								
									
										168
									
								
								src/ArgParse.c
									
									
									
									
									
								
							
							
						
						
									
										168
									
								
								src/ArgParse.c
									
									
									
									
									
								
							| @@ -12,7 +12,7 @@ static bool _COLOR    = true; // 是否启用颜色 | ||||
|  | ||||
| void argParseDisableAutoHelp() { _AutoHelp = false; } | ||||
|  | ||||
| ArgParse *argParseInit(char *documentation) { | ||||
| ArgParse *argParseInit(char *documentation, ArgParseValueType value_type) { | ||||
|     ArgParse *argParse = malloc(sizeof(ArgParse)); | ||||
|     if (argParse == NULL) { | ||||
|         return NULL; | ||||
| @@ -26,6 +26,9 @@ ArgParse *argParseInit(char *documentation) { | ||||
|     argParse->argc            = 0; | ||||
|     argParse->argv            = NULL; | ||||
|     argParse->documentation   = stringNewCopy(documentation); | ||||
|     argParse->value_type      = value_type; | ||||
|     argParse->val             = NULL; | ||||
|     argParse->val_len         = 0; | ||||
|  | ||||
|     argParseAutoHelp(argParse); | ||||
|  | ||||
| @@ -259,7 +262,16 @@ void __freeCommand(Command *command) { | ||||
|     free(command->sub_commands); | ||||
|     free(command->name); | ||||
|     free(command->help); | ||||
|     free(command->args); | ||||
|     free(command->default_val); | ||||
|  | ||||
|     if (command->val_len > 0) { | ||||
|         for (size_t i = 0; i < command->val_len; i++) { | ||||
|             free(command->val[i]); | ||||
|         } | ||||
|         free(command->val); | ||||
|     } | ||||
|  | ||||
|     free(command); | ||||
| } | ||||
|  | ||||
| @@ -274,7 +286,15 @@ void argParseFree(ArgParse *argParse) { | ||||
|     for (size_t i = 0; i < argParse->global_args_len; i++) { | ||||
|         __freeCommandArgs(argParse->global_args[i]); | ||||
|     } | ||||
|     if (argParse->val_len > 0) { | ||||
|         for (size_t i = 0; i < argParse->val_len; i++) { | ||||
|             free(argParse->val[i]); | ||||
|         } | ||||
|         free(argParse->val); | ||||
|     } | ||||
|  | ||||
|     free(argParse->global_args); | ||||
|     free(argParse->documentation); | ||||
|     free(argParse); | ||||
| } | ||||
| /** End----------------内存释放API---------------- */ | ||||
| @@ -369,25 +389,79 @@ int __processSubCommand(ArgParse *argParse, | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| int __processVal(ArgParse *argParse, int index) { | ||||
|     CommandArgs *arg = NULL; | ||||
|  | ||||
|     for (int i = index; i < argParse->argc; i++) { | ||||
|         ArgType argType = checkArgType(argParse->argv[i]); | ||||
|         switch (argType) { | ||||
|         case COMMAND: | ||||
|             argParseSetVal(argParse, argParse->argv[i]); | ||||
|             break; | ||||
|         case LONG_ARG: | ||||
|             // 处理全局命令长选项 | ||||
|             arg = argParseFindGlobalArgs(argParse, argParse->argv[i], false); | ||||
|             if (arg == NULL) { | ||||
|                 char *msg = argParseGenerateArgErrorMsg( | ||||
|                     argParse, argParse->argv[i], false); | ||||
|                 argParseError(argParse, argParse->current_command, msg, NULL); | ||||
|                 return -1; | ||||
|             } | ||||
|             i = __processArgs(argParse, arg, i); | ||||
|             break; | ||||
|         case SHORT_ARG: | ||||
|             // 处理全局命令短选项 | ||||
|             arg = argParseFindGlobalArgs(argParse, argParse->argv[i], true); | ||||
|             if (arg == NULL) { | ||||
|                 char *msg = argParseGenerateArgErrorMsg( | ||||
|                     argParse, argParse->argv[i], true); | ||||
|                 argParseError(argParse, argParse->current_command, msg, NULL); | ||||
|                 return -1; // 错误处理 | ||||
|             } | ||||
|             i = __processArgs( | ||||
|                 argParse, arg, i); // 解析参数值并返回以解析到的索引位置 | ||||
|             break; | ||||
|         default: | ||||
|             argParseError( | ||||
|                 argParse, argParse->current_command, "unknown error", NULL); | ||||
|             return -1; | ||||
|         } | ||||
|     } | ||||
|     return argParse->argc - 1; | ||||
| } | ||||
|  | ||||
| // 处理命令参数 | ||||
|  | ||||
| int __processCommand(ArgParse *argParse, char *name, int command_index) { | ||||
|     Command *command = argParseFindCommand(argParse, name); | ||||
|     if (command == NULL) { | ||||
|     CommandArgs *arg     = NULL; | ||||
|     Command     *command = NULL; | ||||
|  | ||||
|         argParseError(argParse, command, "Command not found", NULL); | ||||
|     command              = argParseFindCommand(argParse, name); // 查找命令 | ||||
|  | ||||
|     if (command == NULL && argParse->value_type == NOVALUE) { | ||||
|         char *msg = NULL; | ||||
|         if (name != NULL) { | ||||
|             msg = stringNewCopy("\033[1;31mERROR\033[0m:"); | ||||
|             __catStr(&msg, 1, name); | ||||
|             __catStr(&msg, 1, " is not a valid command"); | ||||
|         } | ||||
|  | ||||
|         argParseError(argParse, command, msg, NULL); | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     command->is_trigged       = true; // 标记命令被触发 | ||||
|     if (command == NULL && argParse->value_type != NOVALUE) { | ||||
|         return __processVal(argParse, command_index); | ||||
|     } | ||||
|  | ||||
|     CommandArgs *arg          = NULL; | ||||
|     if (command != NULL) { | ||||
|         command->is_trigged       = true; // 标记命令被触发 | ||||
|         argParse->current_command = command; | ||||
|     } | ||||
|  | ||||
|     for (int i = command_index + 1; i < argParse->argc; i++) { | ||||
|         ArgType argType = checkArgType(argParse->argv[i]); | ||||
|         switch (argType) { | ||||
|         case COMMAND: | ||||
|         case COMMAND: { | ||||
|             // 命令无值则处理子命令 | ||||
|             if (command->value_type == NOVALUE) { | ||||
|                 __processSubCommand(argParse, command, argParse->argv[i], i); | ||||
| @@ -397,6 +471,7 @@ int __processCommand(ArgParse *argParse, char *name, int command_index) { | ||||
|                 argParseSetCommandVal(command, argParse->argv[i]); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
|         case LONG_ARG: | ||||
|             // 处理命令长选项 | ||||
|             arg = argParseFindCommandArgs(command, argParse->argv[i], false); | ||||
| @@ -462,6 +537,7 @@ void argParseParse(ArgParse *argParse, int argc, char *argv[]) { | ||||
|         ArgType argType = checkArgType(argv[i]); | ||||
|         switch (argType) { | ||||
|         case COMMAND: | ||||
|             // 处理命令 | ||||
|             i = __processCommand(argParse, argv[i], i); | ||||
|             break; | ||||
|         case LONG_ARG: // 处理全局长选项 | ||||
| @@ -638,44 +714,27 @@ char **argParseGetGlobalArgList(ArgParse *argParse, char *opt, int *len) { | ||||
|     return arg->val; | ||||
| } | ||||
|  | ||||
| size_t __getStrlen(char *str) { | ||||
|     if (str == NULL) { | ||||
|         return 0; | ||||
| char **argParseGetValList(ArgParse *argParse, int *len) { | ||||
|     if (argParse == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
|     return strlen(str); | ||||
|  | ||||
|     if (argParse->val_len == 0) { | ||||
|         return NULL; | ||||
|     } | ||||
|     *len = argParse->val_len; | ||||
|     return argParse->val; | ||||
| } | ||||
|  | ||||
| void __catStr(char **dst, int count, ...) { | ||||
|     va_list args; | ||||
|     va_start(args, count); | ||||
|  | ||||
|     size_t total_len = 0; | ||||
|     total_len        = __getStrlen(*dst); | ||||
|  | ||||
|     // 计算总长度 | ||||
|     char *temp       = NULL; | ||||
|     for (int i = 0; i < count; i++) { | ||||
|         temp = va_arg(args, char *); | ||||
|         total_len += __getStrlen(temp); | ||||
|     } | ||||
|     va_end(args); | ||||
|  | ||||
|     // 分配内存 | ||||
|     *dst = realloc(*dst, total_len + 1); // +1 是为了存储字符串结束符 '\0' | ||||
|     if (*dst == NULL) { | ||||
|         va_end(args); | ||||
|         return; // 处理内存分配失败 | ||||
| char *argParseGetVal(ArgParse *argParse) { | ||||
|     if (argParse == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     // 拼接字符串 | ||||
|     va_start(args, count); | ||||
|     temp = NULL; | ||||
|     for (int i = 0; i < count; i++) { | ||||
|         temp = va_arg(args, char *); | ||||
|         strcat(*dst, temp); | ||||
|     if (argParse->val_len == 0) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     va_end(args); | ||||
|     return argParse->val[0]; | ||||
| } | ||||
|  | ||||
| char *argParseGenerateHelpForCommand(Command *command) { | ||||
| @@ -761,23 +820,39 @@ bool argParseCheckCommandTriggered(ArgParse *argParse, char *command_name) { | ||||
|  | ||||
| _Noreturn void argParseError(ArgParse   *argParse, | ||||
|                              Command    *lastCommand, | ||||
|                              char     *prefix, | ||||
|                              char     *suffix) { | ||||
|                              const char *prefix, | ||||
|                              const char *suffix) { | ||||
|     if (argParse == NULL) { | ||||
|         printf("ERROR: Parse is NULL\n"); | ||||
|         exit(1); | ||||
|     } | ||||
|     if (lastCommand == NULL) { | ||||
|         char *mgs = stringNewCopy(""); | ||||
|         if (prefix != NULL) { | ||||
|             __catStr(&mgs, 1, prefix); | ||||
|         } | ||||
|         char *help = argParseGenerateHelp(argParse); | ||||
|         printf("\033[1;31mERROR\033[0m: Last command is unknown\n"); | ||||
|         printf("%s\n", help); | ||||
|  | ||||
|         if (help != NULL) { | ||||
|             __catStr(&mgs, 2, "\n", help); | ||||
|         } | ||||
|  | ||||
|         if (suffix != NULL) { | ||||
|             __catStr(&mgs, 2, "\n", suffix); | ||||
|         } | ||||
|  | ||||
|         // printf("\033[1;31mERROR\033[0m: Last command is unknown\n"); | ||||
|         printf("%s\n", mgs); | ||||
|         free(mgs); | ||||
|         free(help); | ||||
|         argParseFree(argParse); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     char *ErrorMsg = NULL; | ||||
|  | ||||
|     if (prefix != NULL) { | ||||
|         ErrorMsg = stringNewCopy(prefix); | ||||
|         ErrorMsg = stringNewCopy((char *)prefix); | ||||
|     } | ||||
|  | ||||
|     char *command_help_msg     = argParseGenerateHelpForCommand(lastCommand); | ||||
| @@ -794,8 +869,7 @@ _Noreturn void argParseError(ArgParse *argParse, | ||||
|     printf("%s\n", ErrorMsg); | ||||
|     free(ErrorMsg); | ||||
|     free(command_help_msg); | ||||
|     free(prefix); | ||||
|     free(suffix); | ||||
|     argParseFree(argParse); | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| #include "ArgParseTools.h" | ||||
| #include "ArgParse.h" | ||||
| #include <stdarg.h> | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| @@ -243,3 +245,84 @@ bool argParseSetCommandVal(Command *command, char *val) { | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief 设置解析值,该值为程序所需的无命令值例如`gcc mian.c`的`main.c` | ||||
|  * @param argParse 解析器 | ||||
|  * @param val 值 | ||||
|  * @return 成功返回true,失败返回false | ||||
|  */ | ||||
| bool argParseSetVal(ArgParse *argParse, char *val) { | ||||
|  | ||||
|     if (argParse->value_type == MULTIVALUE) { // 多值 | ||||
|         argParse->val = | ||||
|             realloc(argParse->val, (argParse->val_len + 1) * sizeof(char *)); | ||||
|         if (argParse->val == NULL) { | ||||
|             return false; | ||||
|         } | ||||
|         argParse->val[argParse->val_len] = stringNewCopy(val); | ||||
|         if (argParse->val[argParse->val_len] == NULL) { | ||||
|             return false; | ||||
|         } | ||||
|         argParse->val_len++; | ||||
|         return true; | ||||
|     } else if (argParse->value_type == SINGLEVALUE) { // 单值 | ||||
|         if (argParse->val != NULL) { | ||||
|             free(argParse->val); | ||||
|         } | ||||
|         argParse->val = malloc(sizeof(char *)); | ||||
|  | ||||
|         if (argParse->val == NULL) { | ||||
|             return false; | ||||
|         } | ||||
|         argParse->val[0] = stringNewCopy(val); // 分配内存 | ||||
|         if (argParse->val[0] == NULL) { | ||||
|             return false; | ||||
|         } | ||||
|         argParse->val_len = 1; | ||||
|         return true; | ||||
|     } else if (argParse->value_type == NOVALUE) { // 无值 | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| size_t __getStrlen(char *str) { | ||||
|     if (str == NULL) { | ||||
|         return 0; | ||||
|     } | ||||
|     return strlen(str); | ||||
| } | ||||
|  | ||||
| void __catStr(char **dst, int count, ...) { | ||||
|     va_list args; | ||||
|     va_start(args, count); | ||||
|  | ||||
|     size_t total_len = 0; | ||||
|     total_len        = __getStrlen(*dst); | ||||
|  | ||||
|     // 计算总长度 | ||||
|     char *temp       = NULL; | ||||
|     for (int i = 0; i < count; i++) { | ||||
|         temp = va_arg(args, char *); | ||||
|         total_len += __getStrlen(temp); | ||||
|     } | ||||
|     va_end(args); | ||||
|  | ||||
|     // 分配内存 | ||||
|     *dst = realloc(*dst, total_len + 1); // +1 是为了存储字符串结束符 '\0' | ||||
|     if (*dst == NULL) { | ||||
|         va_end(args); | ||||
|         return; // 处理内存分配失败 | ||||
|     } | ||||
|  | ||||
|     // 拼接字符串 | ||||
|     va_start(args, count); | ||||
|     temp = NULL; | ||||
|     for (int i = 0; i < count; i++) { | ||||
|         temp = va_arg(args, char *); | ||||
|         strcat(*dst, temp); | ||||
|     } | ||||
|  | ||||
|     va_end(args); | ||||
| } | ||||
| @@ -3,6 +3,7 @@ | ||||
|  | ||||
| #include "ArgParse.h" | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| @@ -45,6 +46,8 @@ bool argParseSetArgVal(CommandArgs *args, char *val); // 设置命令参数值 | ||||
|  | ||||
| bool argParseSetCommandVal(Command *command, char *val); // 设置命令值 | ||||
|  | ||||
| bool argParseSetVal(ArgParse *argParse, char *val); // 设置值 | ||||
|  | ||||
| ArgType checkArgType(char *arg); // 检查参数类型 | ||||
|  | ||||
| Command *argParseFindCommand(ArgParse *argParse, char *name); // 查找命令 | ||||
| @@ -60,6 +63,8 @@ CommandArgs *argParseFindGlobalArgs(ArgParse *argParse, | ||||
|                                     bool      short_flag); // 查找全局参数 | ||||
|  | ||||
| char  *stringNewCopy(char *str);             // 创建字符串副本 | ||||
| void   __catStr(char **dst, int count, ...); // 字符串拼接 | ||||
| size_t __getStrlen(char *str);               // 获取字符串长度 | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|   | ||||
| @@ -32,3 +32,8 @@ add_executable(${PROJECT_NAME}unknow_command_arg test_unknow_command.c) | ||||
| target_link_libraries(${PROJECT_NAME}unknow_command_arg CArgParse) | ||||
| add_test(${PROJECT_NAME}unknow_command_arg ${PROJECT_NAME}unknow_command_arg install --unknow) | ||||
| set_tests_properties(${PROJECT_NAME}unknow_command_arg PROPERTIES WILL_FAIL TRUE) | ||||
|  | ||||
| # 未知命令选项测试,预期打印该命令的帮助信息 | ||||
| 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) | ||||
| @@ -4,7 +4,7 @@ | ||||
| #include <string.h> | ||||
|  | ||||
| ArgParse *initArgParse() { | ||||
|     ArgParse *argparse    = argParseInit("测试程序"); | ||||
|     ArgParse *argparse    = argParseInit("测试程序",NOVALUE); | ||||
|     Command  *command     = NULL; | ||||
|     Command  *sub_command = NULL; | ||||
|  | ||||
|   | ||||
							
								
								
									
										122
									
								
								tests/test_val.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								tests/test_val.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| #include "ArgParse.h" | ||||
| #include <assert.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| ArgParse *initArgParse() { | ||||
|     ArgParse *argparse    = argParseInit("测试程序", MULTIVALUE); | ||||
|     Command  *command     = NULL; | ||||
|     Command  *sub_command = NULL; | ||||
|  | ||||
|     // add global arguments | ||||
|     argParseAddGlobalArg(argparse, | ||||
|                          "-v", | ||||
|                          "--version", | ||||
|                          "Show version", | ||||
|                          NULL, | ||||
|                          NULL, | ||||
|                          false, | ||||
|                          NOVALUE); | ||||
|     argParseAddGlobalArg( | ||||
|         argparse, "-q", "--quiet", "Quiet mode", NULL, NULL, false, NOVALUE); | ||||
|  | ||||
|     // add arguments | ||||
|     command = argParseAddCommand( | ||||
|         argparse, "install", "Install the package", NULL, NULL, NULL, NOVALUE); | ||||
|     argParseAddArg(command, | ||||
|                    "-i", | ||||
|                    "--index", | ||||
|                    "Index URL", | ||||
|                    "https://example.com", | ||||
|                    NULL, | ||||
|                    false, | ||||
|                    SINGLEVALUE); | ||||
|     argParseAddArg(command, | ||||
|                    "-f", | ||||
|                    "--file", | ||||
|                    "Package file", | ||||
|                    "package.json", | ||||
|                    NULL, | ||||
|                    false, | ||||
|                    MULTIVALUE); | ||||
|     argParseAddArg(command, | ||||
|                    "-p", | ||||
|                    "--package", | ||||
|                    "Package file", | ||||
|                    "package.json", | ||||
|                    NULL, | ||||
|                    false, | ||||
|                    MULTIVALUE); | ||||
|  | ||||
|     sub_command = argParseAddSubCommand( | ||||
|         command, "tools", "Install tools", NULL, NULL, NULL, MULTIVALUE); | ||||
|  | ||||
|     argParseAddArg(sub_command, | ||||
|                    "-t", | ||||
|                    "--tool", | ||||
|                    "Tool name", | ||||
|                    "Tool name", | ||||
|                    NULL, | ||||
|                    true, | ||||
|                    MULTIVALUE); | ||||
|     sub_command = argParseAddSubCommand( | ||||
|         command, "tools_sub", "Install tools", NULL, NULL, NULL, MULTIVALUE); | ||||
|  | ||||
|     argParseAddArg(sub_command, | ||||
|                    "-s", | ||||
|                    "--source", | ||||
|                    "test_source", | ||||
|                    "tools subcommand test", | ||||
|                    NULL, | ||||
|                    true, | ||||
|                    MULTIVALUE); | ||||
|  | ||||
|     command = argParseAddCommand(argparse, | ||||
|                                  "uninstall", | ||||
|                                  "Uninstall the package", | ||||
|                                  NULL, | ||||
|                                  NULL, | ||||
|                                  NULL, | ||||
|                                  SINGLEVALUE); | ||||
|     argParseAddArg(command, | ||||
|                    "-p", | ||||
|                    "--package", | ||||
|                    "Package name", | ||||
|                    "Package name", | ||||
|                    NULL, | ||||
|                    true, | ||||
|                    MULTIVALUE); | ||||
|  | ||||
|     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, "-q")); | ||||
|  | ||||
|     argParseFree(argparse); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user