feat: v0.2.0
This commit is contained in:
		
							
								
								
									
										246
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,246 @@ | |||||||
|  | --- | ||||||
|  | Language:        Cpp | ||||||
|  | # BasedOnStyle:  LLVM | ||||||
|  | AccessModifierOffset: -2 | ||||||
|  | AlignAfterOpenBracket: Align | ||||||
|  | AlignArrayOfStructures: None | ||||||
|  | AlignConsecutiveAssignments: | ||||||
|  |   Enabled:         true | ||||||
|  |   AcrossEmptyLines: true | ||||||
|  |   AcrossComments:  true | ||||||
|  |   AlignCompound:   false | ||||||
|  |   AlignFunctionPointers: false | ||||||
|  |   PadOperators:    true | ||||||
|  | AlignConsecutiveBitFields: | ||||||
|  |   Enabled:         true | ||||||
|  |   AcrossEmptyLines: false | ||||||
|  |   AcrossComments:  false | ||||||
|  |   AlignCompound:   false | ||||||
|  |   AlignFunctionPointers: false | ||||||
|  |   PadOperators:    false | ||||||
|  | AlignConsecutiveDeclarations: | ||||||
|  |   Enabled:         true | ||||||
|  |   AcrossEmptyLines: false | ||||||
|  |   AcrossComments:  false | ||||||
|  |   AlignCompound:   false | ||||||
|  |   AlignFunctionPointers: false | ||||||
|  |   PadOperators:    false | ||||||
|  | AlignConsecutiveMacros: | ||||||
|  |   Enabled:         true | ||||||
|  |   AcrossEmptyLines: false | ||||||
|  |   AcrossComments:  false | ||||||
|  |   AlignCompound:   false | ||||||
|  |   AlignFunctionPointers: false | ||||||
|  |   PadOperators:    false | ||||||
|  | AlignConsecutiveShortCaseStatements: | ||||||
|  |   Enabled:         false | ||||||
|  |   AcrossEmptyLines: false | ||||||
|  |   AcrossComments:  false | ||||||
|  |   AlignCaseColons: false | ||||||
|  | AlignEscapedNewlines: Right | ||||||
|  | AlignOperands:   Align | ||||||
|  | AlignTrailingComments: | ||||||
|  |   Kind:            Always | ||||||
|  |   OverEmptyLines:  0 | ||||||
|  | AllowAllArgumentsOnNextLine: true | ||||||
|  | AllowAllParametersOfDeclarationOnNextLine: true | ||||||
|  | AllowBreakBeforeNoexceptSpecifier: Never | ||||||
|  | AllowShortBlocksOnASingleLine: Never | ||||||
|  | AllowShortCaseLabelsOnASingleLine: false | ||||||
|  | AllowShortCompoundRequirementOnASingleLine: true | ||||||
|  | AllowShortEnumsOnASingleLine: true | ||||||
|  | AllowShortFunctionsOnASingleLine: All | ||||||
|  | AllowShortIfStatementsOnASingleLine: Never | ||||||
|  | AllowShortLambdasOnASingleLine: All | ||||||
|  | AllowShortLoopsOnASingleLine: false | ||||||
|  | AlwaysBreakAfterDefinitionReturnType: None | ||||||
|  | AlwaysBreakAfterReturnType: None | ||||||
|  | AlwaysBreakBeforeMultilineStrings: false | ||||||
|  | AlwaysBreakTemplateDeclarations: MultiLine | ||||||
|  | AttributeMacros: | ||||||
|  |   - __capability | ||||||
|  | BinPackArguments: false | ||||||
|  | BinPackParameters: false | ||||||
|  | BitFieldColonSpacing: Both | ||||||
|  | BraceWrapping: | ||||||
|  |   AfterCaseLabel:  false | ||||||
|  |   AfterClass:      false | ||||||
|  |   AfterControlStatement: Never | ||||||
|  |   AfterEnum:       false | ||||||
|  |   AfterExternBlock: false | ||||||
|  |   AfterFunction:   false | ||||||
|  |   AfterNamespace:  false | ||||||
|  |   AfterObjCDeclaration: false | ||||||
|  |   AfterStruct:     false | ||||||
|  |   AfterUnion:      false | ||||||
|  |   BeforeCatch:     false | ||||||
|  |   BeforeElse:      false | ||||||
|  |   BeforeLambdaBody: false | ||||||
|  |   BeforeWhile:     false | ||||||
|  |   IndentBraces:    false | ||||||
|  |   SplitEmptyFunction: true | ||||||
|  |   SplitEmptyRecord: true | ||||||
|  |   SplitEmptyNamespace: true | ||||||
|  | BreakAdjacentStringLiterals: true | ||||||
|  | BreakAfterAttributes: Leave | ||||||
|  | BreakAfterJavaFieldAnnotations: false | ||||||
|  | BreakArrays:     true | ||||||
|  | BreakBeforeBinaryOperators: None | ||||||
|  | BreakBeforeConceptDeclarations: Always | ||||||
|  | BreakBeforeBraces: Attach | ||||||
|  | BreakBeforeInlineASMColon: OnlyMultiline | ||||||
|  | BreakBeforeTernaryOperators: true | ||||||
|  | BreakConstructorInitializers: BeforeColon | ||||||
|  | BreakInheritanceList: BeforeColon | ||||||
|  | BreakStringLiterals: true | ||||||
|  | ColumnLimit:     80 | ||||||
|  | CommentPragmas:  '^ IWYU pragma:' | ||||||
|  | CompactNamespaces: false | ||||||
|  | ConstructorInitializerIndentWidth: 4 | ||||||
|  | ContinuationIndentWidth: 4 | ||||||
|  | Cpp11BracedListStyle: true | ||||||
|  | DerivePointerAlignment: false | ||||||
|  | DisableFormat:   false | ||||||
|  | EmptyLineAfterAccessModifier: Never | ||||||
|  | EmptyLineBeforeAccessModifier: LogicalBlock | ||||||
|  | ExperimentalAutoDetectBinPacking: false | ||||||
|  | FixNamespaceComments: true | ||||||
|  | ForEachMacros: | ||||||
|  |   - foreach | ||||||
|  |   - Q_FOREACH | ||||||
|  |   - BOOST_FOREACH | ||||||
|  | IfMacros: | ||||||
|  |   - KJ_IF_MAYBE | ||||||
|  | IncludeBlocks:   Preserve | ||||||
|  | IncludeCategories: | ||||||
|  |   - Regex:           '^"(llvm|llvm-c|clang|clang-c)/' | ||||||
|  |     Priority:        2 | ||||||
|  |     SortPriority:    0 | ||||||
|  |     CaseSensitive:   false | ||||||
|  |   - Regex:           '^(<|"(gtest|gmock|isl|json)/)' | ||||||
|  |     Priority:        3 | ||||||
|  |     SortPriority:    0 | ||||||
|  |     CaseSensitive:   false | ||||||
|  |   - Regex:           '.*' | ||||||
|  |     Priority:        1 | ||||||
|  |     SortPriority:    0 | ||||||
|  |     CaseSensitive:   false | ||||||
|  | IncludeIsMainRegex: '(Test)?$' | ||||||
|  | IncludeIsMainSourceRegex: '' | ||||||
|  | IndentAccessModifiers: false | ||||||
|  | IndentCaseBlocks: false | ||||||
|  | IndentCaseLabels: false | ||||||
|  | IndentExternBlock: AfterExternBlock | ||||||
|  | IndentGotoLabels: true | ||||||
|  | IndentPPDirectives: None | ||||||
|  | IndentRequiresClause: true | ||||||
|  | IndentWidth:     4 | ||||||
|  | IndentWrappedFunctionNames: false | ||||||
|  | InsertBraces:    false | ||||||
|  | InsertNewlineAtEOF: false | ||||||
|  | InsertTrailingCommas: None | ||||||
|  | IntegerLiteralSeparator: | ||||||
|  |   Binary:          0 | ||||||
|  |   BinaryMinDigits: 0 | ||||||
|  |   Decimal:         0 | ||||||
|  |   DecimalMinDigits: 0 | ||||||
|  |   Hex:             0 | ||||||
|  |   HexMinDigits:    0 | ||||||
|  | JavaScriptQuotes: Leave | ||||||
|  | JavaScriptWrapImports: true | ||||||
|  | KeepEmptyLinesAtTheStartOfBlocks: true | ||||||
|  | KeepEmptyLinesAtEOF: false | ||||||
|  | LambdaBodyIndentation: Signature | ||||||
|  | LineEnding:      DeriveLF | ||||||
|  | MacroBlockBegin: '' | ||||||
|  | MacroBlockEnd:   '' | ||||||
|  | MaxEmptyLinesToKeep: 1 | ||||||
|  | NamespaceIndentation: None | ||||||
|  | ObjCBinPackProtocolList: Auto | ||||||
|  | ObjCBlockIndentWidth: 2 | ||||||
|  | ObjCBreakBeforeNestedBlockParam: true | ||||||
|  | ObjCSpaceAfterProperty: false | ||||||
|  | ObjCSpaceBeforeProtocolList: true | ||||||
|  | PackConstructorInitializers: BinPack | ||||||
|  | PenaltyBreakAssignment: 2 | ||||||
|  | PenaltyBreakBeforeFirstCallParameter: 19 | ||||||
|  | PenaltyBreakComment: 300 | ||||||
|  | PenaltyBreakFirstLessLess: 120 | ||||||
|  | PenaltyBreakOpenParenthesis: 0 | ||||||
|  | PenaltyBreakScopeResolution: 500 | ||||||
|  | PenaltyBreakString: 1000 | ||||||
|  | PenaltyBreakTemplateDeclaration: 10 | ||||||
|  | PenaltyExcessCharacter: 1000000 | ||||||
|  | PenaltyIndentedWhitespace: 0 | ||||||
|  | PenaltyReturnTypeOnItsOwnLine: 60 | ||||||
|  | PointerAlignment: Right | ||||||
|  | PPIndentWidth:   -1 | ||||||
|  | QualifierAlignment: Leave | ||||||
|  | ReferenceAlignment: Pointer | ||||||
|  | ReflowComments:  true | ||||||
|  | RemoveBracesLLVM: false | ||||||
|  | RemoveParentheses: Leave | ||||||
|  | RemoveSemicolon: false | ||||||
|  | RequiresClausePosition: OwnLine | ||||||
|  | RequiresExpressionIndentation: OuterScope | ||||||
|  | SeparateDefinitionBlocks: Leave | ||||||
|  | ShortNamespaceLines: 1 | ||||||
|  | SkipMacroDefinitionBody: false | ||||||
|  | SortIncludes:    CaseSensitive | ||||||
|  | SortJavaStaticImport: Before | ||||||
|  | SortUsingDeclarations: LexicographicNumeric | ||||||
|  | SpaceAfterCStyleCast: false | ||||||
|  | SpaceAfterLogicalNot: false | ||||||
|  | SpaceAfterTemplateKeyword: true | ||||||
|  | SpaceAroundPointerQualifiers: Default | ||||||
|  | SpaceBeforeAssignmentOperators: true | ||||||
|  | SpaceBeforeCaseColon: false | ||||||
|  | SpaceBeforeCpp11BracedList: false | ||||||
|  | SpaceBeforeCtorInitializerColon: true | ||||||
|  | SpaceBeforeInheritanceColon: true | ||||||
|  | SpaceBeforeJsonColon: false | ||||||
|  | SpaceBeforeParens: ControlStatements | ||||||
|  | SpaceBeforeParensOptions: | ||||||
|  |   AfterControlStatements: true | ||||||
|  |   AfterForeachMacros: true | ||||||
|  |   AfterFunctionDefinitionName: false | ||||||
|  |   AfterFunctionDeclarationName: false | ||||||
|  |   AfterIfMacros:   true | ||||||
|  |   AfterOverloadedOperator: false | ||||||
|  |   AfterPlacementOperator: true | ||||||
|  |   AfterRequiresInClause: false | ||||||
|  |   AfterRequiresInExpression: false | ||||||
|  |   BeforeNonEmptyParentheses: false | ||||||
|  | SpaceBeforeRangeBasedForLoopColon: true | ||||||
|  | SpaceBeforeSquareBrackets: false | ||||||
|  | SpaceInEmptyBlock: false | ||||||
|  | SpacesBeforeTrailingComments: 1 | ||||||
|  | SpacesInAngles:  Never | ||||||
|  | SpacesInContainerLiterals: true | ||||||
|  | SpacesInLineCommentPrefix: | ||||||
|  |   Minimum:         1 | ||||||
|  |   Maximum:         -1 | ||||||
|  | SpacesInParens:  Never | ||||||
|  | SpacesInParensOptions: | ||||||
|  |   InCStyleCasts:   false | ||||||
|  |   InConditionalStatements: false | ||||||
|  |   InEmptyParentheses: false | ||||||
|  |   Other:           false | ||||||
|  | SpacesInSquareBrackets: false | ||||||
|  | Standard:        Latest | ||||||
|  | StatementAttributeLikeMacros: | ||||||
|  |   - Q_EMIT | ||||||
|  | StatementMacros: | ||||||
|  |   - Q_UNUSED | ||||||
|  |   - QT_REQUIRE_VERSION | ||||||
|  | TabWidth:        8 | ||||||
|  | UseTab:          Never | ||||||
|  | VerilogBreakBetweenInstancePorts: true | ||||||
|  | WhitespaceSensitiveMacros: | ||||||
|  |   - BOOST_PP_STRINGIZE | ||||||
|  |   - CF_SWIFT_NAME | ||||||
|  |   - NS_SWIFT_NAME | ||||||
|  |   - PP_STRINGIZE | ||||||
|  |   - STRINGIZE | ||||||
|  | ... | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | *.png filter=lfs diff=lfs merge=lfs -text | ||||||
							
								
								
									
										72
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | # ---> C | ||||||
|  | # Prerequisites | ||||||
|  | *.d | ||||||
|  |  | ||||||
|  | # Object files | ||||||
|  | *.o | ||||||
|  | *.ko | ||||||
|  | *.obj | ||||||
|  | *.elf | ||||||
|  |  | ||||||
|  | # Linker output | ||||||
|  | *.ilk | ||||||
|  | *.map | ||||||
|  | *.exp | ||||||
|  |  | ||||||
|  | # Precompiled Headers | ||||||
|  | *.gch | ||||||
|  | *.pch | ||||||
|  |  | ||||||
|  | # Libraries | ||||||
|  | *.lib | ||||||
|  | *.a | ||||||
|  | *.la | ||||||
|  | *.lo | ||||||
|  |  | ||||||
|  | # Shared objects (inc. Windows DLLs) | ||||||
|  | *.dll | ||||||
|  | *.so | ||||||
|  | *.so.* | ||||||
|  | *.dylib | ||||||
|  |  | ||||||
|  | # Executables | ||||||
|  | *.exe | ||||||
|  | *.out | ||||||
|  | *.app | ||||||
|  | *.i*86 | ||||||
|  | *.x86_64 | ||||||
|  | *.hex | ||||||
|  |  | ||||||
|  | # Debug files | ||||||
|  | *.dSYM/ | ||||||
|  | *.su | ||||||
|  | *.idb | ||||||
|  | *.pdb | ||||||
|  |  | ||||||
|  | # Kernel Module Compile Results | ||||||
|  | *.mod* | ||||||
|  | *.cmd | ||||||
|  | .tmp_versions/ | ||||||
|  | modules.order | ||||||
|  | Module.symvers | ||||||
|  | Mkfile.old | ||||||
|  | dkms.conf | ||||||
|  |  | ||||||
|  | # ---> CMake | ||||||
|  | CMakeLists.txt.user | ||||||
|  | CMakeCache.txt | ||||||
|  | CMakeFiles | ||||||
|  | CMakeScripts | ||||||
|  | Testing | ||||||
|  | Makefile | ||||||
|  | cmake_install.cmake | ||||||
|  | install_manifest.txt | ||||||
|  | compile_commands.json | ||||||
|  | CTestTestfile.cmake | ||||||
|  | _deps | ||||||
|  | CMakeUserPresets.json | ||||||
|  |  | ||||||
|  |  | ||||||
|  | build | ||||||
|  | .cache | ||||||
|  | .vscode | ||||||
							
								
								
									
										1
									
								
								.python-version
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.python-version
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | 3.13 | ||||||
							
								
								
									
										44
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | cmake_minimum_required(VERSION 3.28) | ||||||
|  |  | ||||||
|  | project(CArgParse) | ||||||
|  |  | ||||||
|  | if(MSVC) | ||||||
|  |     add_compile_options(/utf-8) | ||||||
|  | endif(MSVC) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | option(SHARED_BUILD "Build shared library" OFF) | ||||||
|  | option(TEST "Build tests" ON) | ||||||
|  | option(EXAMPLE "Build examples" ON) | ||||||
|  |  | ||||||
|  | set(CMAKE_C_STANDARD 11) | ||||||
|  |  | ||||||
|  | enable_testing() | ||||||
|  |  | ||||||
|  | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||||||
|  |  | ||||||
|  | include_directories(include) | ||||||
|  |  | ||||||
|  | aux_source_directory(src SRC) | ||||||
|  |  | ||||||
|  | if(SHARED_BUILD) | ||||||
|  |     message(STATUS "Building shared library") | ||||||
|  |     add_library(${PROJECT_NAME} SHARED ${SRC}) | ||||||
|  | else() | ||||||
|  |     message(STATUS "Building static library") | ||||||
|  |     add_library(${PROJECT_NAME} ${SRC}) | ||||||
|  | endif(SHARED_BUILD) | ||||||
|  |  | ||||||
|  | if(TEST) | ||||||
|  |     add_subdirectory(tests) | ||||||
|  | endif(TEST) | ||||||
|  |  | ||||||
|  | if(EXAMPLE) | ||||||
|  |     add_subdirectory(examples) | ||||||
|  | endif(EXAMPLE) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # install | ||||||
|  | install(TARGETS ${PROJECT_NAME} DESTINATION lib) | ||||||
|  | install(FILES include/CArgParse.h DESTINATION include) | ||||||
							
								
								
									
										80
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | |||||||
|  | # CArgParse | ||||||
|  |  | ||||||
|  | C语言易用的命令参数分析 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # 特性 | ||||||
|  | - 自动生成帮助信息 | ||||||
|  | - 默认值支持 | ||||||
|  | - 子命令支持 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # 安装 | ||||||
|  |  | ||||||
|  | ## cmake安装 | ||||||
|  | ```bash | ||||||
|  | cmake -S . -B build | ||||||
|  | cmake --build build | ||||||
|  | cmake --install build | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## conan安装 | ||||||
|  | 将库构建为`conan`包 | ||||||
|  | ```bash | ||||||
|  | conan create . | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## 示例程序 | ||||||
|  | 构建简单的命令行程序 | ||||||
|  | ```c | ||||||
|  | #include "ArgParse.h" | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | ArgParse *Init() { | ||||||
|  |     ArgParse *ap = argParseInit("简单的命令行工具示例"); | ||||||
|  |  | ||||||
|  |     // 添加第一个命令 | ||||||
|  |     Command *cmd = argParseAddCommand( | ||||||
|  |         ap, "list", "列出文件列表", NULL, NULL, NULL, SINGLEVALUE); | ||||||
|  |  | ||||||
|  |     // 添加第一个命令的参数 | ||||||
|  |     argParseAddArg(cmd, | ||||||
|  |                    "-a", | ||||||
|  |                    "--all", | ||||||
|  |                    "列出所有文件包括隐藏文件", | ||||||
|  |                    NULL, | ||||||
|  |                    NULL, | ||||||
|  |                    false, | ||||||
|  |                    NOVALUE); | ||||||
|  |  | ||||||
|  |     return ap; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) { | ||||||
|  |     ArgParse *ap = Init(); | ||||||
|  |     argParseParse(ap, argc, argv); | ||||||
|  |  | ||||||
|  |     char *dir = argParseGetCurCommandValue(ap); | ||||||
|  |     if (dir != NULL) { | ||||||
|  |         printf("列出目录: %s 的文件列表\n", dir); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (argParseCheckCurArgTriggered(ap, "-a")) { | ||||||
|  |         printf("触发了 -a 参数,列出所有文件\n"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     argParseFree(ap); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | example -h | ||||||
|  | ``` | ||||||
|  |  | ||||||
							
								
								
									
										112
									
								
								conanfile.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								conanfile.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | |||||||
|  | from conan import ConanFile | ||||||
|  | from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout | ||||||
|  | from conan.tools.files import copy | ||||||
|  | import os | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class loggingRecipe(ConanFile): | ||||||
|  |     name = "cargparse" | ||||||
|  |     version = "0.2.0" | ||||||
|  |     license = "MIT" | ||||||
|  |     author = "321640253@qq.com" | ||||||
|  |     url = "https://gitea.youmetme.wang/youmetme/logging" | ||||||
|  |     description = "C语言命令行参数解析器" | ||||||
|  |     topics = ( | ||||||
|  |         "argparse", | ||||||
|  |         "C", | ||||||
|  |         "simple", | ||||||
|  |         "easy-to-use", | ||||||
|  |         "CArgParse", | ||||||
|  |         "args", | ||||||
|  |         "cargparse", | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     settings = "os", "compiler", "build_type", "arch" | ||||||
|  |     options = { | ||||||
|  |         "shared": [True, False], | ||||||
|  |         "fPIC": [True, False], | ||||||
|  |         "test": [True, False], | ||||||
|  |         "example": [True, False], | ||||||
|  |     } | ||||||
|  |     default_options = {"shared": False, "fPIC": True, "test": True, "example": False} | ||||||
|  |  | ||||||
|  |     exports_sources = "include/*", "CMakeLists.txt", "src/*", "tests/*" | ||||||
|  |  | ||||||
|  |     def config_options(self): | ||||||
|  |         if self.settings.os == "Windows": | ||||||
|  |             del self.options.fPIC | ||||||
|  |  | ||||||
|  |     def configure(self): | ||||||
|  |         if self.options.shared: | ||||||
|  |             self.options.rm_safe("fPIC") | ||||||
|  |  | ||||||
|  |     def layout(self): | ||||||
|  |         cmake_layout(self) | ||||||
|  |  | ||||||
|  |     def generate(self): | ||||||
|  |         deps = CMakeDeps(self) | ||||||
|  |         deps.generate() | ||||||
|  |         tc = CMakeToolchain(self) | ||||||
|  |         tc.variables["TEST"] = True if self.options.test else False | ||||||
|  |         tc.variables["SHARED_BUILD"] = True if self.options.shared else False | ||||||
|  |         tc.variables["EXAMPLE"] = True if self.options.example else False | ||||||
|  |         tc.generate() | ||||||
|  |  | ||||||
|  |     def build(self): | ||||||
|  |         cmake = CMake(self) | ||||||
|  |         cmake.configure() | ||||||
|  |         cmake.build() | ||||||
|  |         if self.options.test: | ||||||
|  |             cmake.test() | ||||||
|  |  | ||||||
|  |     def package(self): | ||||||
|  |         copy( | ||||||
|  |             self, | ||||||
|  |             "LICENSE", | ||||||
|  |             src=self.source_folder, | ||||||
|  |             dst=os.path.join(self.package_folder, "licenses"), | ||||||
|  |         ) | ||||||
|  |         copy( | ||||||
|  |             self, | ||||||
|  |             pattern="*.h", | ||||||
|  |             src=os.path.join(self.source_folder, "include"), | ||||||
|  |             dst=os.path.join(self.package_folder, "include"), | ||||||
|  |         ) | ||||||
|  |         copy( | ||||||
|  |             self, | ||||||
|  |             pattern="*.a", | ||||||
|  |             src=self.build_folder, | ||||||
|  |             dst=os.path.join(self.package_folder, "lib"), | ||||||
|  |             keep_path=False, | ||||||
|  |         ) | ||||||
|  |         copy( | ||||||
|  |             self, | ||||||
|  |             pattern="*.so", | ||||||
|  |             src=self.build_folder, | ||||||
|  |             dst=os.path.join(self.package_folder, "lib"), | ||||||
|  |             keep_path=False, | ||||||
|  |         ) | ||||||
|  |         copy( | ||||||
|  |             self, | ||||||
|  |             pattern="*.lib", | ||||||
|  |             src=self.build_folder, | ||||||
|  |             dst=os.path.join(self.package_folder, "lib"), | ||||||
|  |             keep_path=False, | ||||||
|  |         ) | ||||||
|  |         copy( | ||||||
|  |             self, | ||||||
|  |             pattern="*.dll", | ||||||
|  |             src=self.build_folder, | ||||||
|  |             dst=os.path.join(self.package_folder, "bin"), | ||||||
|  |             keep_path=False, | ||||||
|  |         ) | ||||||
|  |         copy( | ||||||
|  |             self, | ||||||
|  |             pattern="*.dylib", | ||||||
|  |             src=self.build_folder, | ||||||
|  |             dst=os.path.join(self.package_folder, "lib"), | ||||||
|  |             keep_path=False, | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     def package_info(self): | ||||||
|  |         self.cpp_info.libs = ["cargparse"] | ||||||
							
								
								
									
										
											BIN
										
									
								
								docs/images/help.png
									
									LFS
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/images/help.png
									
									LFS
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										5
									
								
								examples/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								examples/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | project(example) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | add_executable(example simple.c) | ||||||
|  | target_link_libraries(example CArgParse) | ||||||
							
								
								
									
										41
									
								
								examples/simple.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								examples/simple.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | #include "ArgParse.h" | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | ArgParse *Init() { | ||||||
|  |     ArgParse *ap = argParseInit("简单的命令行工具示例"); | ||||||
|  |  | ||||||
|  |     // 添加第一个命令 | ||||||
|  |     Command *cmd = argParseAddCommand( | ||||||
|  |         ap, "list", "列出文件列表", NULL, NULL, NULL, SINGLEVALUE); | ||||||
|  |  | ||||||
|  |     // 添加第一个命令的参数 | ||||||
|  |     argParseAddArg(cmd, | ||||||
|  |                    "-a", | ||||||
|  |                    "--all", | ||||||
|  |                    "列出所有文件包括隐藏文件", | ||||||
|  |                    NULL, | ||||||
|  |                    NULL, | ||||||
|  |                    false, | ||||||
|  |                    NOVALUE); | ||||||
|  |  | ||||||
|  |     return ap; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) { | ||||||
|  |     ArgParse *ap = Init(); | ||||||
|  |     argParseParse(ap, argc, argv); | ||||||
|  |  | ||||||
|  |     char *dir = argParseGetCurCommandValue(ap); | ||||||
|  |     if (dir != NULL) { | ||||||
|  |         printf("列出目录: %s 的文件列表\n", dir); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (argParseCheckCurArgTriggered(ap, "-a")) { | ||||||
|  |         printf("触发了 -a 参数,列出所有文件\n"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     argParseFree(ap); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										306
									
								
								include/ArgParse.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								include/ArgParse.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,306 @@ | |||||||
|  | #ifndef CARGPARSE_H | ||||||
|  | #define CARGPARSE_H | ||||||
|  |  | ||||||
|  | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #define ARG_DEFAULT_HELP_FLAG "--help" | ||||||
|  |  | ||||||
|  | typedef struct ArgParse ArgParse; // 解析器 | ||||||
|  |  | ||||||
|  | typedef int (*ArgParseCallback)(ArgParse *argParse, | ||||||
|  |                                 char    **val, | ||||||
|  |                                 int       val_len); // 回调函数 | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     NOVALUE = 0,     // 无值 | ||||||
|  |     SINGLEVALUE,     // 单值 例如: -i https://www.baidu.com | ||||||
|  |     MULTIVALUE,      // 多值 例如: -s a b c 或 -s a -s b -s c等 | ||||||
|  | } ArgParseValueType; // 值类型 | ||||||
|  |  | ||||||
|  | typedef struct CommandArgs { | ||||||
|  |     /* 构造属性 */ | ||||||
|  |     char             *short_opt;   // 短选项名, 例如: -h | ||||||
|  |     char             *long_opt;    // 长选项    例如: --help | ||||||
|  |     char             *default_val; // 默认值 | ||||||
|  |     char             *help;        // 选项帮助信息 | ||||||
|  |     ArgParseCallback  callback;    // 回调函数 | ||||||
|  |     bool              required;    // 是否为必选参数 | ||||||
|  |     ArgParseValueType value_type;  // 值类型 | ||||||
|  |     /* 解析所用到的属性*/ | ||||||
|  |     char **val;        // 解析到的值 | ||||||
|  |     int    val_len;    // 解析到的值个数 | ||||||
|  |     bool   is_trigged; // 是否被触发 | ||||||
|  | } CommandArgs; | ||||||
|  |  | ||||||
|  | typedef struct CommandGroup { | ||||||
|  |     char            *name;         // 命令组名 | ||||||
|  |     char            *help;         // 命令组帮助信息 | ||||||
|  |     struct Command **commands;     // 命令 | ||||||
|  |     int              commands_len; // 命令个数 | ||||||
|  | } CommandGroup; | ||||||
|  |  | ||||||
|  | typedef struct Command { | ||||||
|  |     /* 构造属性 */ | ||||||
|  |     char                *name;             // 命令名 | ||||||
|  |     char                *help;             // 命令帮助信息 | ||||||
|  |     CommandGroup        *group;            // 命令组 | ||||||
|  |     char                *default_val;      // 默认值 | ||||||
|  |     struct CommandArgs **args;             // 命令参数 | ||||||
|  |     int                  args_len;         // 命令参数个数 | ||||||
|  |     struct Command     **sub_commands;     // 子命令 | ||||||
|  |     int                  sub_commands_len; // 子命令个数 | ||||||
|  |     ArgParseCallback     callback;         // 回调函数 | ||||||
|  |     ArgParseValueType    value_type;       // 值类型 | ||||||
|  |  | ||||||
|  |     /* 解析所用到的属性*/ | ||||||
|  |     char **val;        // 解析到的值 | ||||||
|  |     int    val_len;    // 解析到的值个数 | ||||||
|  |     bool   is_trigged; // 是否被触发 | ||||||
|  | } Command; | ||||||
|  |  | ||||||
|  | typedef struct ArgParse { | ||||||
|  |     /* 构造属性 */ | ||||||
|  |     struct Command     **commands;        // 命令 | ||||||
|  |     int                  commands_len;    // 命令个数 | ||||||
|  |     struct CommandArgs **global_args;     // 全局参数 | ||||||
|  |     int                  global_args_len; // 全局参数个数 | ||||||
|  |     char                *documentation;   // 帮助文档 | ||||||
|  |     /* 解析所用到的属性*/ | ||||||
|  |     struct Command *current_command; // 当前解析到的命令 | ||||||
|  |     int             argc;            // 参数个数 | ||||||
|  |     char          **argv;            // 参数列表 | ||||||
|  | } ArgParse; | ||||||
|  |  | ||||||
|  | /** Start---------------构造API---------------- */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 初始化解析器 | ||||||
|  |  * @return ArgParse* 解析器指针 | ||||||
|  |  */ | ||||||
|  | ArgParse *argParseInit(char *documentation); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 释放解析器 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @return void | ||||||
|  |  */ | ||||||
|  | void argParseFree(ArgParse *argParse); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 自动生成帮助信息 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @return void | ||||||
|  |  */ | ||||||
|  | void argParseAutoHelp(ArgParse *argParse); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 添加命令 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param name 命令名 | ||||||
|  |  * @param help 命令帮助信息 | ||||||
|  |  * @param group_name 命令组名 | ||||||
|  |  * @return Command* 命令指针 | ||||||
|  |  */ | ||||||
|  | Command *argParseAddCommand(ArgParse         *argParse, | ||||||
|  |                             char             *name, | ||||||
|  |                             char             *help, | ||||||
|  |                             char             *default_val, // 默认值 | ||||||
|  |                             ArgParseCallback  callback, | ||||||
|  |                             CommandGroup     *group, | ||||||
|  |                             ArgParseValueType value_type); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 添加子命令 | ||||||
|  |  * @param Parent 父命令指针 | ||||||
|  |  * @param name 命令名 | ||||||
|  |  * @param help 命令帮助信息 | ||||||
|  |  * @param callback 回调函数 | ||||||
|  |  * @param value_type 值类型 | ||||||
|  |  * @return Command* 子命令指针 | ||||||
|  |  */ | ||||||
|  | Command *argParseAddSubCommand(Command          *Parent, | ||||||
|  |                                char             *name, | ||||||
|  |                                char             *help, | ||||||
|  |                                char             *default_val, | ||||||
|  |                                ArgParseCallback  callback, | ||||||
|  |                                CommandGroup     *group, | ||||||
|  |                                ArgParseValueType value_type); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 添加命令参数 | ||||||
|  |  * @param command 命令指针 | ||||||
|  |  * @param long_opt 长选项名 | ||||||
|  |  * @param short_opt 短选项名 | ||||||
|  |  * @param default_val 默认值 | ||||||
|  |  * @param help 选项帮助信息 | ||||||
|  |  * @param required 是否为必选参数 | ||||||
|  |  * @param value_type 值类型 | ||||||
|  |  * @return CommandArgs* 参数指针 | ||||||
|  |  */ | ||||||
|  | CommandArgs *argParseAddArg(Command          *command, | ||||||
|  |                             char             *short_opt, | ||||||
|  |                             char             *long_opt, | ||||||
|  |                             char             *help, | ||||||
|  |                             char             *default_val, | ||||||
|  |                             ArgParseCallback  callback, | ||||||
|  |                             bool              required, | ||||||
|  |                             ArgParseValueType value_type); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 添加全局参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param short_opt 短选项名 | ||||||
|  |  * @param long_opt 长选项名 | ||||||
|  |  * @param default_val 默认值 | ||||||
|  |  * @param help 选项帮助信息 | ||||||
|  |  * @param required 是否为必选参数 | ||||||
|  |  * @param value_type 值类型 | ||||||
|  |  * @return | ||||||
|  |  */ | ||||||
|  | CommandArgs *argParseAddGlobalArg(ArgParse         *argParse, | ||||||
|  |                                   char             *short_opt, | ||||||
|  |                                   char             *long_opt, | ||||||
|  |                                   char             *help, | ||||||
|  |                                   char             *default_val, | ||||||
|  |                                   ArgParseCallback  callback, | ||||||
|  |                                   bool              required, | ||||||
|  |                                   ArgParseValueType value_type); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 禁用自动生成帮助信息 | ||||||
|  |  */ | ||||||
|  | void argParseDisableAutoHelp(); | ||||||
|  |  | ||||||
|  | /** End---------------构造API---------------- */ | ||||||
|  |  | ||||||
|  | /** Start----------------解析API---------------- */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 解析命令行参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param argc 参数个数 | ||||||
|  |  * @param argv 参数列表 | ||||||
|  |  */ | ||||||
|  | void argParseParse(ArgParse *argParse, int argc, char *argv[]); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 获取当前解析到的命令名 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @return char* 命令名 | ||||||
|  |  */ | ||||||
|  | char *argParseGetCurCommandName(ArgParse *argParse); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 获取当前解析到的命令的值,针对带值参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @return char* 命令值 | ||||||
|  |  */ | ||||||
|  | char *argParseGetCurCommandValue(ArgParse *argParse); | ||||||
|  | /** | ||||||
|  |  * @brief 获取当前解析到的命令的值列表,针对带值参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param len 值个数buffer | ||||||
|  |  * @return char** 命令值列表 | ||||||
|  |  */ | ||||||
|  | char **argParseGetCurCommandValues(ArgParse *argParse, int *len); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief | ||||||
|  |  * 获取当前解析到的命令的参数,当前命令为解析到的最后一个命令或者命令的子命令 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param opt 选项名 | ||||||
|  |  * @return char* 选项值 | ||||||
|  |  * @return | ||||||
|  |  */ | ||||||
|  | char *argParseGetCurArg(ArgParse *argParse, char *opt); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 获取当前解析到的命令参数列表,仅适用于多值参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param opt 选项名 | ||||||
|  |  * @param len 参数个数buffer | ||||||
|  |  * @return char** 参数列表 | ||||||
|  |  */ | ||||||
|  | char **argParseGetCurArgList(ArgParse *argParse, char *opt, int *len); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 获取全局参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param opt 选项名 | ||||||
|  |  * @return char* 选项值 | ||||||
|  |  */ | ||||||
|  | char *argParseGetGlobalArg(ArgParse *argParse, char *opt); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 获取全局参数列表,仅适用于多值参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param opt 选项名 | ||||||
|  |  * @param len 参数个数buffer | ||||||
|  |  * @return char** 参数列表 | ||||||
|  |  */ | ||||||
|  | char **argParseGetGlobalArgList(ArgParse *argParse, char *opt, int *len); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 检查当前解析到的命令的某个参数是否被触发 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param opt 选项名 | ||||||
|  |  * @return bool 是否被触发 | ||||||
|  |  */ | ||||||
|  | bool argParseCheckCurArgTriggered(ArgParse *argParse, char *opt); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 检查当前解析到的命令是否被触发 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param command_name 命令名 | ||||||
|  |  * @return bool 是否被触发 | ||||||
|  |  */ | ||||||
|  | bool argParseCheckCommandTriggered(ArgParse *argParse, char *command_name); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 检查全局参数是否被触发 | ||||||
|  |  * @param  argParse 解析器指针 | ||||||
|  |  * @param   opt 选项名 | ||||||
|  |  * @return bool 是否被触发 | ||||||
|  |  */ | ||||||
|  | bool argParseCheckGlobalTriggered(ArgParse *argParse, char *opt); | ||||||
|  |  | ||||||
|  | /** End----------------解析API---------------- */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 生成命令帮助信息 | ||||||
|  |  * @param   command 命令指针 | ||||||
|  |  * @return  char* 命令帮助信息 | ||||||
|  |  */ | ||||||
|  | char *argParseGenerateHelpForCommand(Command *command); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 生成全局参数帮助信息 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @return  char* 全局参数帮助信息 | ||||||
|  |  */ | ||||||
|  | char *argParseGenerateHelp(ArgParse *argParse); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 生成选项错误信息 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param name 选项名 | ||||||
|  |  * @param short_flag 是否为短选项 | ||||||
|  |  * @return char* 选项错误信息 | ||||||
|  |  */ | ||||||
|  | char * | ||||||
|  | argParseGenerateArgErrorMsg(ArgParse *argParse, char *name, bool short_flag); | ||||||
|  |  | ||||||
|  | _Noreturn void argParseError(ArgParse *argParse, | ||||||
|  |                              Command  *lastCommand, | ||||||
|  |                              char     *prefix, | ||||||
|  |                              char     *suffix); | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif // __cplusplus | ||||||
|  |  | ||||||
|  | #endif // CARGPARSE_H | ||||||
							
								
								
									
										9
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | [project] | ||||||
|  | name = "cargparse" | ||||||
|  | version = "0.1.0" | ||||||
|  | description = "Add your description here" | ||||||
|  | readme = "README.md" | ||||||
|  | requires-python = ">=3.13" | ||||||
|  | dependencies = [ | ||||||
|  |     "conan>=2.18.1", | ||||||
|  | ] | ||||||
							
								
								
									
										874
									
								
								src/ArgParse.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										874
									
								
								src/ArgParse.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,874 @@ | |||||||
|  | #include "ArgParse.h" | ||||||
|  | #include "ArgParseTools.h" | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | static bool _AutoHelp = true; // 是否自动添加帮助信息 | ||||||
|  | static bool _COLOR    = true; // 是否启用颜色 | ||||||
|  |  | ||||||
|  | void argParseDisableAutoHelp() { _AutoHelp = false; } | ||||||
|  |  | ||||||
|  | ArgParse *argParseInit(char *documentation) { | ||||||
|  |     ArgParse *argParse = malloc(sizeof(ArgParse)); | ||||||
|  |     if (argParse == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     argParse->commands        = NULL; | ||||||
|  |     argParse->commands_len    = 0; | ||||||
|  |     argParse->current_command = NULL; | ||||||
|  |     argParse->global_args     = NULL; | ||||||
|  |     argParse->global_args_len = 0; | ||||||
|  |     argParse->argc            = 0; | ||||||
|  |     argParse->argv            = NULL; | ||||||
|  |     argParse->documentation   = stringNewCopy(documentation); | ||||||
|  |  | ||||||
|  |     argParseAutoHelp(argParse); | ||||||
|  |  | ||||||
|  |     return argParse; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 自动帮助信息回调函数 | ||||||
|  |  */ | ||||||
|  | int __helpCallback(ArgParse *argParse, char **val, int val_len) { | ||||||
|  |     if (argParse == NULL) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     char *help_doc = argParseGenerateHelp(argParse); | ||||||
|  |     printf("%s\n", help_doc); | ||||||
|  |     free(help_doc); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 自动添加帮助信息 | ||||||
|  |  * @param argParse ArgParse结构体指针 | ||||||
|  |  */ | ||||||
|  | void argParseAutoHelp(ArgParse *argParse) { | ||||||
|  |     if (!_AutoHelp) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     if (argParse == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     argParseAddGlobalArg(argParse, | ||||||
|  |                          "-h", | ||||||
|  |                          "--help", | ||||||
|  |                          "show help", | ||||||
|  |                          NULL, | ||||||
|  |                          __helpCallback, | ||||||
|  |                          false, | ||||||
|  |                          NOVALUE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int __commandHelpCallback(ArgParse *argParse, char **val, int val_len) { | ||||||
|  |     if (argParse == NULL) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     char *help_doc = argParseGenerateHelpForCommand(argParse->current_command); | ||||||
|  |     printf("%s", help_doc); | ||||||
|  |     free(help_doc); | ||||||
|  |     exit(0); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void argParseCommandAutoHelp(Command *command) { | ||||||
|  |     if (!_AutoHelp) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     if (command == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     argParseAddArg(command, | ||||||
|  |                    "-h", | ||||||
|  |                    "--help", | ||||||
|  |                    "show help", | ||||||
|  |                    NULL, | ||||||
|  |                    __commandHelpCallback, | ||||||
|  |                    false, | ||||||
|  |                    NOVALUE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Command *argParseAddCommand(ArgParse         *argParse, | ||||||
|  |                             char             *name, | ||||||
|  |                             char             *help, | ||||||
|  |                             char             *default_val, | ||||||
|  |                             ArgParseCallback  callback, | ||||||
|  |                             CommandGroup     *group, | ||||||
|  |                             ArgParseValueType value_type) { | ||||||
|  |  | ||||||
|  |     if (argParse == NULL || name == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     // 构造命令结构 | ||||||
|  |     Command *command = | ||||||
|  |         createCommand(name, help, default_val, callback, group, value_type); | ||||||
|  |  | ||||||
|  |     // 将命令结构添加到argParse中 | ||||||
|  |     argParse->commands = realloc( | ||||||
|  |         argParse->commands, sizeof(Command *) * (argParse->commands_len + 1)); | ||||||
|  |     if (argParse->commands == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     argParse->commands[argParse->commands_len] = command; | ||||||
|  |     argParse->commands_len++; | ||||||
|  |  | ||||||
|  |     argParseCommandAutoHelp(command); | ||||||
|  |  | ||||||
|  |     return command; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 添加子命令 | ||||||
|  |  * @param Parent 父命令 | ||||||
|  |  * @param name 子命令名称 | ||||||
|  |  * @param help 子命令帮助信息 | ||||||
|  |  * @param callback 子命令回调函数 | ||||||
|  |  * @param group 子命令组 | ||||||
|  |  * @param value_type 子命令值类型 | ||||||
|  |  * @return | ||||||
|  |  */ | ||||||
|  | Command *argParseAddSubCommand(Command          *Parent, | ||||||
|  |                                char             *name, | ||||||
|  |                                char             *help, | ||||||
|  |                                char             *default_val, | ||||||
|  |                                ArgParseCallback  callback, | ||||||
|  |                                CommandGroup     *group, | ||||||
|  |                                ArgParseValueType value_type) { | ||||||
|  |  | ||||||
|  |     if (Parent == NULL || name == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     // 构造命令结构 | ||||||
|  |     Command *command = | ||||||
|  |         createCommand(name, help, default_val, callback, group, value_type); | ||||||
|  |     if (command == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     // 将命令结构添加到Parent中 | ||||||
|  |     Parent->sub_commands = | ||||||
|  |         realloc(Parent->sub_commands, | ||||||
|  |                 sizeof(Command *) * (Parent->sub_commands_len + 1)); | ||||||
|  |     if (Parent->sub_commands == NULL) | ||||||
|  |         return NULL; | ||||||
|  |     Parent->sub_commands[Parent->sub_commands_len] = command; | ||||||
|  |     Parent->sub_commands_len++; | ||||||
|  |  | ||||||
|  |     argParseCommandAutoHelp(command); | ||||||
|  |  | ||||||
|  |     return command; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CommandArgs *argParseAddArg(Command          *command, | ||||||
|  |                             char             *short_opt, | ||||||
|  |                             char             *long_opt, | ||||||
|  |                             char             *help, | ||||||
|  |                             char             *default_val, | ||||||
|  |                             ArgParseCallback  callback, | ||||||
|  |                             bool              required, | ||||||
|  |                             ArgParseValueType value_type) { | ||||||
|  |  | ||||||
|  |     if (command == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     // 构造参数结构 | ||||||
|  |     CommandArgs *arg = createCommandArgs( | ||||||
|  |         short_opt, long_opt, default_val, help, callback, required, value_type); | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     // 将参数结构添加到command中 | ||||||
|  |     command->args = | ||||||
|  |         realloc(command->args, sizeof(CommandArgs *) * (command->args_len + 1)); | ||||||
|  |     if (command->args == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     command->args[command->args_len] = arg; | ||||||
|  |     command->args_len++; | ||||||
|  |  | ||||||
|  |     return arg; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CommandArgs *argParseAddGlobalArg(ArgParse         *argParse, | ||||||
|  |                                   char             *short_opt, | ||||||
|  |                                   char             *long_opt, | ||||||
|  |                                   char             *help, | ||||||
|  |                                   char             *default_val, | ||||||
|  |                                   ArgParseCallback  callback, | ||||||
|  |                                   bool              required, | ||||||
|  |                                   ArgParseValueType value_type) { | ||||||
|  |  | ||||||
|  |     if (argParse == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     // 构造参数结构 | ||||||
|  |     CommandArgs *arg = createCommandArgs( | ||||||
|  |         short_opt, long_opt, default_val, help, callback, required, value_type); | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     // 将参数结构添加到argParse中 | ||||||
|  |     argParse->global_args = | ||||||
|  |         realloc(argParse->global_args, | ||||||
|  |                 sizeof(CommandArgs *) * (argParse->global_args_len + 1)); | ||||||
|  |     if (argParse->global_args == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     argParse->global_args[argParse->global_args_len] = arg; | ||||||
|  |     argParse->global_args_len++; | ||||||
|  |  | ||||||
|  |     return arg; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Start----------------内存释放API---------------- */ | ||||||
|  | void __freeCommandArgs(CommandArgs *arg) { | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     free(arg->short_opt); | ||||||
|  |     free(arg->long_opt); | ||||||
|  |     free(arg->help); | ||||||
|  |     free(arg->default_val); | ||||||
|  |     for (size_t i = 0; i < arg->val_len; i++) { | ||||||
|  |         free(arg->val[i]); | ||||||
|  |     } | ||||||
|  |     free(arg->val); | ||||||
|  |     free(arg); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void __freeCommand(Command *command) { | ||||||
|  |     if (command == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < command->args_len; i++) { | ||||||
|  |         __freeCommandArgs(command->args[i]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < command->sub_commands_len; i++) { | ||||||
|  |         __freeCommand(command->sub_commands[i]); | ||||||
|  |     } | ||||||
|  |     free(command->sub_commands); | ||||||
|  |     free(command->name); | ||||||
|  |     free(command->help); | ||||||
|  |     free(command->default_val); | ||||||
|  |     free(command); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void argParseFree(ArgParse *argParse) { | ||||||
|  |     // 释放命令及其子命令与参数 | ||||||
|  |     for (size_t i = 0; i < argParse->commands_len; i++) { | ||||||
|  |         __freeCommand(argParse->commands[i]); | ||||||
|  |     } | ||||||
|  |     free(argParse->commands); | ||||||
|  |  | ||||||
|  |     // 释放全局参数 | ||||||
|  |     for (size_t i = 0; i < argParse->global_args_len; i++) { | ||||||
|  |         __freeCommandArgs(argParse->global_args[i]); | ||||||
|  |     } | ||||||
|  |     free(argParse->global_args); | ||||||
|  |     free(argParse); | ||||||
|  | } | ||||||
|  | /** End----------------内存释放API---------------- */ | ||||||
|  |  | ||||||
|  | /** Start----------------解析API---------------- */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 解析命令行参数 | ||||||
|  |  * @param argParse ArgParse结构体指针 | ||||||
|  |  * @param command 命令结构体指针 | ||||||
|  |  * @param arg 参数结构体指针 | ||||||
|  |  * @param arg_index 参数索引 | ||||||
|  |  * @return int 返回解析到的参数索引 | ||||||
|  |  */ | ||||||
|  | int __processArgs(ArgParse *argParse, CommandArgs *arg, int arg_index) { | ||||||
|  |     arg->is_trigged   = true; // 标记参数被触发 | ||||||
|  |  | ||||||
|  |     int current_index = arg_index; | ||||||
|  |  | ||||||
|  |     if (arg->value_type == MULTIVALUE) { | ||||||
|  |         for (int i = arg_index + 1; i < argParse->argc; i++) { | ||||||
|  |             if (checkArgType(argParse->argv[i]) == | ||||||
|  |                 COMMAND) { // COMMAND是无--或-开头的字符串,也可认定为参数值 | ||||||
|  |                 argParseSetArgVal(arg, argParse->argv[i]); | ||||||
|  |                 current_index = i; | ||||||
|  |             } else { | ||||||
|  |                 current_index = i - 1; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } else if (arg->value_type == SINGLEVALUE) { | ||||||
|  |         if (arg_index + 1 < argParse->argc) { | ||||||
|  |             argParseSetArgVal(arg, argParse->argv[arg_index + 1]); | ||||||
|  |             current_index = arg_index + 1; | ||||||
|  |         } | ||||||
|  |     } else if (arg->value_type == NOVALUE) { | ||||||
|  |         current_index = arg_index; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (arg->callback != NULL) { | ||||||
|  |         arg->callback(argParse, arg->val, arg->val_len); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return current_index; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 处理子命令参数 | ||||||
|  | int __processSubCommand(ArgParse *argParse, | ||||||
|  |                         Command  *ParentCommand, | ||||||
|  |                         char     *name, | ||||||
|  |                         int       command_index) { | ||||||
|  |  | ||||||
|  |     Command *sub_command = argParseFindSubCommand(ParentCommand, name); | ||||||
|  |     if (sub_command == NULL) { | ||||||
|  |         argParseError(argParse, argParse->current_command, NULL, NULL); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     CommandArgs *arg          = NULL; | ||||||
|  |  | ||||||
|  |     argParse->current_command = sub_command; | ||||||
|  |  | ||||||
|  |     for (int i = command_index + 1; i < argParse->argc; i++) { | ||||||
|  |         ArgType argType = checkArgType(argParse->argv[i]); | ||||||
|  |         switch (argType) { | ||||||
|  |         case COMMAND: | ||||||
|  |             return __processSubCommand( | ||||||
|  |                 argParse, sub_command, argParse->argv[i], i); // 递归处理子命令 | ||||||
|  |         case LONG_ARG: | ||||||
|  |             arg = | ||||||
|  |                 argParseFindCommandArgs(sub_command, argParse->argv[i], false); | ||||||
|  |             if (arg != NULL) { | ||||||
|  |                 i = __processArgs(argParse, arg, i); | ||||||
|  |             } | ||||||
|  |             return i; | ||||||
|  |         case SHORT_ARG: | ||||||
|  |             arg = argParseFindCommandArgs(sub_command, argParse->argv[i], true); | ||||||
|  |             if (arg != NULL) { | ||||||
|  |                 i = __processArgs(argParse, | ||||||
|  |                                   arg, | ||||||
|  |                                   i); // 解析参数值并返回以解析到的索引位置 | ||||||
|  |                 return i; | ||||||
|  |             } else { | ||||||
|  |                 argParseError(argParse, argParse->current_command, NULL, NULL); | ||||||
|  |                 return -1; | ||||||
|  |             } | ||||||
|  |         default: | ||||||
|  |             argParseError(argParse, argParse->current_command, NULL, NULL); | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     argParseError(argParse, argParse->current_command, NULL, NULL); | ||||||
|  |     return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 处理命令参数 | ||||||
|  |  | ||||||
|  | int __processCommand(ArgParse *argParse, char *name, int command_index) { | ||||||
|  |     Command *command = argParseFindCommand(argParse, name); | ||||||
|  |     if (command == NULL) { | ||||||
|  |  | ||||||
|  |         argParseError(argParse, command, "Command not found", NULL); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     command->is_trigged       = true; // 标记命令被触发 | ||||||
|  |  | ||||||
|  |     CommandArgs *arg          = NULL; | ||||||
|  |     argParse->current_command = command; | ||||||
|  |  | ||||||
|  |     for (int i = command_index + 1; i < argParse->argc; i++) { | ||||||
|  |         ArgType argType = checkArgType(argParse->argv[i]); | ||||||
|  |         switch (argType) { | ||||||
|  |         case COMMAND: | ||||||
|  |             // 命令无值则处理子命令 | ||||||
|  |             if (command->value_type == NOVALUE) { | ||||||
|  |                 __processSubCommand(argParse, command, argParse->argv[i], i); | ||||||
|  |                 return argParse->argc - 1; | ||||||
|  |             } else { | ||||||
|  |                 // 命令有值,则认为该值是命令值 | ||||||
|  |                 argParseSetCommandVal(command, argParse->argv[i]); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case LONG_ARG: | ||||||
|  |             // 处理命令长选项 | ||||||
|  |             arg = argParseFindCommandArgs(command, argParse->argv[i], false); | ||||||
|  |             if (arg == NULL) { | ||||||
|  |                 // 可能全局参数被放在了命令参数之前 | ||||||
|  |                 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; | ||||||
|  |             } | ||||||
|  |             i = __processArgs(argParse, arg, i); | ||||||
|  |             break; | ||||||
|  |         case SHORT_ARG: | ||||||
|  |             // 处理命令短选项 | ||||||
|  |             arg = argParseFindCommandArgs(command, argParse->argv[i], true); | ||||||
|  |             if (arg == NULL) { | ||||||
|  |                 // 可能全局参数被放在了命令参数之前 | ||||||
|  |                 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; | ||||||
|  |             } | ||||||
|  |             i = __processArgs(argParse, | ||||||
|  |                               arg, | ||||||
|  |                               i); // 解析参数值并返回以解析到的索引位置 | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             argParseError(argParse, argParse->current_command, NULL, NULL); | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return argParse->argc - 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 解析命令行参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param argc 参数个数 | ||||||
|  |  * @param argv 参数列表 | ||||||
|  |  */ | ||||||
|  | void argParseParse(ArgParse *argParse, int argc, char *argv[]) { | ||||||
|  |     argParse->argc   = argc; | ||||||
|  |     argParse->argv   = argv; | ||||||
|  |  | ||||||
|  |     CommandArgs *arg = NULL; | ||||||
|  |  | ||||||
|  |     for (int i = 1; i < argc; i++) { | ||||||
|  |         ArgType argType = checkArgType(argv[i]); | ||||||
|  |         switch (argType) { | ||||||
|  |         case COMMAND: | ||||||
|  |             i = __processCommand(argParse, argv[i], i); | ||||||
|  |             break; | ||||||
|  |         case LONG_ARG: // 处理全局长选项 | ||||||
|  |             arg = argParseFindGlobalArgs(argParse, argv[i], false); | ||||||
|  |             if (arg == NULL) { | ||||||
|  |                 char *msg = | ||||||
|  |                     argParseGenerateArgErrorMsg(argParse, argv[i], false); | ||||||
|  |                 argParseError(argParse, argParse->current_command, msg, NULL); | ||||||
|  |                 return; // 错误处理 | ||||||
|  |             } | ||||||
|  |             i = __processArgs(argParse, arg, i); | ||||||
|  |             break; | ||||||
|  |         case SHORT_ARG: // 处理全局短选项 | ||||||
|  |             arg = argParseFindGlobalArgs(argParse, argv[i], true); | ||||||
|  |             if (arg == NULL) { | ||||||
|  |                 char *msg = | ||||||
|  |                     argParseGenerateArgErrorMsg(argParse, argv[i], true); | ||||||
|  |                 argParseError(argParse, argParse->current_command, msg, NULL); | ||||||
|  |                 return; // 错误处理 | ||||||
|  |             } | ||||||
|  |             i = __processArgs( | ||||||
|  |                 argParse, arg, i); // 解析参数值并返回以解析到的索引位置 | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // 执行当前命令的回调函数 | ||||||
|  |     if (argParse->current_command != NULL && | ||||||
|  |         argParse->current_command->is_trigged && | ||||||
|  |         argParse->current_command->callback != NULL) { | ||||||
|  |         argParse->current_command->callback(argParse, | ||||||
|  |                                             argParse->current_command->val, | ||||||
|  |                                             argParse->current_command->val_len); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 获取当前解析到的命令名,会返回最后一个解析到的命令名(子命令) | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @return char* 命令名 | ||||||
|  |  */ | ||||||
|  | char *argParseGetCurCommandName(ArgParse *argParse) { | ||||||
|  |     if (argParse == NULL) | ||||||
|  |         return NULL; | ||||||
|  |  | ||||||
|  |     if (argParse->current_command == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     return argParse->current_command->name; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 获取当前解析到的命令参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param opt 选项名 | ||||||
|  |  * @return char* 选项值 | ||||||
|  |  * @return | ||||||
|  |  */ | ||||||
|  | char *argParseGetCurArg(ArgParse *argParse, char *opt) { | ||||||
|  |     CommandArgs *arg = NULL; | ||||||
|  |     // 尝试获取当前命令的长选项参数 | ||||||
|  |     arg = argParseFindCommandArgs(argParse->current_command, opt, false); | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         // 尝试获取当前命令的短选项参数 | ||||||
|  |         arg = argParseFindCommandArgs(argParse->current_command, opt, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     if (arg->val_len >= 1) { | ||||||
|  |         return arg->val[0]; | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 获取当前解析到的命令参数列表,仅适用于多值参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param opt 选项名 | ||||||
|  |  * @param len 参数个数buffer | ||||||
|  |  * @return char** 参数列表 | ||||||
|  |  */ | ||||||
|  | char **argParseGetCurArgList(ArgParse *argParse, char *opt, int *len) { | ||||||
|  |     CommandArgs *arg = NULL; | ||||||
|  |     arg = argParseFindCommandArgs(argParse->current_command, opt, false); | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         arg = argParseFindCommandArgs(argParse->current_command, opt, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     *len = arg->val_len; | ||||||
|  |     return arg->val; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 获取全局参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param opt 选项名 | ||||||
|  |  * @return char* 选项值 | ||||||
|  |  */ | ||||||
|  | char *argParseGetGlobalArg(ArgParse *argParse, char *opt) { | ||||||
|  |     CommandArgs *arg = NULL; | ||||||
|  |     arg              = argParseFindGlobalArgs(argParse, opt, false); | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         arg = argParseFindGlobalArgs(argParse, opt, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     if (arg->val_len >= 1) { | ||||||
|  |         return arg->val[0]; | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 获取当前解析到的命令参数值 | ||||||
|  |  * @return  char* 参数值 | ||||||
|  |  */ | ||||||
|  | char *argParseGetCurCommandValue(ArgParse *argParse) { | ||||||
|  |     Command *command = argParse->current_command; | ||||||
|  |     if (command == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     if (command->val_len >= 1) { | ||||||
|  |         return command->val[0]; | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  | /** | ||||||
|  |  * @brief 获取当前解析到的命令参数列表,仅适用于多值参数 | ||||||
|  |  * @return char** 参数列表 | ||||||
|  |  */ | ||||||
|  | char **argParseGetCurCommandValues(ArgParse *argParse, int *len) { | ||||||
|  |     Command *command = argParse->current_command; | ||||||
|  |     if (command == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     if (command->val_len >= 1) { | ||||||
|  |         *len = command->val_len; | ||||||
|  |         return command->val; | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 获取全局参数列表,仅适用于多值参数 | ||||||
|  |  * @param argParse 解析器指针 | ||||||
|  |  * @param opt 选项名 | ||||||
|  |  * @param len 参数个数buffer | ||||||
|  |  * @return char** 参数列表 | ||||||
|  |  */ | ||||||
|  | char **argParseGetGlobalArgList(ArgParse *argParse, char *opt, int *len) { | ||||||
|  |     CommandArgs *arg = NULL; | ||||||
|  |     arg              = argParseFindGlobalArgs(argParse, opt, false); | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         arg = argParseFindGlobalArgs(argParse, opt, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     *len = arg->val_len; | ||||||
|  |     return arg->val; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char *argParseGenerateHelpForCommand(Command *command) { | ||||||
|  |     if (command == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     char *help_msg = stringNewCopy(command->help); | ||||||
|  |     if (help_msg == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     __catStr(&help_msg, 1, "\n\n"); | ||||||
|  |     __catStr(&help_msg, 2, "\033[1;33mUsage\033[0m: ", command->name); | ||||||
|  |  | ||||||
|  |     switch (command->value_type) { | ||||||
|  |     case NOVALUE: | ||||||
|  |         break; | ||||||
|  |     case SINGLEVALUE: | ||||||
|  |         __catStr(&help_msg, 1, " <value>"); | ||||||
|  |         break; | ||||||
|  |     case MULTIVALUE: | ||||||
|  |         __catStr(&help_msg, 1, " <value>..."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (command->args != NULL) { | ||||||
|  |         __catStr(&help_msg, 1, " [Options]"); | ||||||
|  |         __catStr(&help_msg, 1, "\n\n\033[1;34mOptions\033[0m:"); | ||||||
|  |         for (int i = 0; i < command->args_len; i++) { | ||||||
|  |             CommandArgs *arg = command->args[i]; | ||||||
|  |  | ||||||
|  |             __catStr(&help_msg, | ||||||
|  |                      6, | ||||||
|  |                      "\n  \033[1;32m", | ||||||
|  |                      arg->short_opt, | ||||||
|  |                      "\033[0m , \033[1;32m", | ||||||
|  |                      arg->long_opt, | ||||||
|  |                      "\033[0m  ", | ||||||
|  |                      arg->help); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     __catStr(&help_msg, 1, "\n"); | ||||||
|  |  | ||||||
|  |     return help_msg; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //  检查全局参数是否被触发 | ||||||
|  | bool argParseCheckGlobalTriggered(ArgParse *argParse, char *opt) { | ||||||
|  |     CommandArgs *arg = NULL; | ||||||
|  |     arg              = argParseFindGlobalArgs(argParse, opt, false); | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         arg = argParseFindGlobalArgs(argParse, opt, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return arg->is_trigged; | ||||||
|  | } | ||||||
|  | // 检测当前命令的某项参数是否被触发 | ||||||
|  | bool argParseCheckCurArgTriggered(ArgParse *argParse, char *opt) { | ||||||
|  |     CommandArgs *arg = NULL; | ||||||
|  |     arg = argParseFindCommandArgs(argParse->current_command, opt, false); | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         arg = argParseFindCommandArgs(argParse->current_command, opt, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (arg == NULL) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return arg->is_trigged; | ||||||
|  | } | ||||||
|  | // 检测指定命令是否被触发 | ||||||
|  | bool argParseCheckCommandTriggered(ArgParse *argParse, char *command_name) { | ||||||
|  |     Command *command = argParseFindCommand(argParse, command_name); | ||||||
|  |     if (command == NULL) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return command->is_trigged; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | _Noreturn void argParseError(ArgParse *argParse, | ||||||
|  |                              Command  *lastCommand, | ||||||
|  |                              char     *prefix, | ||||||
|  |                              char     *suffix) { | ||||||
|  |     if (argParse == NULL) { | ||||||
|  |         printf("ERROR: Parse is NULL\n"); | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
|  |     if (lastCommand == NULL) { | ||||||
|  |         char *help = argParseGenerateHelp(argParse); | ||||||
|  |         printf("\033[1;31mERROR\033[0m: Last command is unknown\n"); | ||||||
|  |         printf("%s\n", help); | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     char *ErrorMsg = NULL; | ||||||
|  |  | ||||||
|  |     if (prefix != NULL) { | ||||||
|  |         ErrorMsg = stringNewCopy(prefix); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     char *command_help_msg     = argParseGenerateHelpForCommand(lastCommand); | ||||||
|  |     int   command_help_msg_len = strlen(command_help_msg); | ||||||
|  |  | ||||||
|  |     if (command_help_msg != NULL) { | ||||||
|  |         __catStr(&ErrorMsg, 2, "\n", command_help_msg); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (suffix != NULL) { | ||||||
|  |         __catStr(&ErrorMsg, 2, "\n", suffix); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     printf("%s\n", ErrorMsg); | ||||||
|  |     free(ErrorMsg); | ||||||
|  |     free(command_help_msg); | ||||||
|  |     free(prefix); | ||||||
|  |     free(suffix); | ||||||
|  |     exit(1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char * | ||||||
|  | argParseGenerateArgErrorMsg(ArgParse *argParse, char *name, bool short_flag) { | ||||||
|  |     if (argParse == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     if (name == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     char *ErrorMsg = NULL; | ||||||
|  |  | ||||||
|  |     if (_COLOR) { | ||||||
|  |         ErrorMsg = stringNewCopy("\033[1;31mERROR\033[0m: Invalid argument "); | ||||||
|  |     } else { | ||||||
|  |         ErrorMsg = stringNewCopy("ERROR: Invalid argument "); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (short_flag) { | ||||||
|  |         __catStr(&ErrorMsg, 1, name); | ||||||
|  |     } else { | ||||||
|  |         __catStr(&ErrorMsg, 1, name); | ||||||
|  |     } | ||||||
|  |     return ErrorMsg; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char *argParseGenerateHelp(ArgParse *argParse) { | ||||||
|  |     if (argParse == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     char *help_msg = stringNewCopy(argParse->documentation); | ||||||
|  |  | ||||||
|  |     if (help_msg == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     __catStr(&help_msg, 1, "\n\n\033[1;34mCommands\033[0m:"); | ||||||
|  |     for (int i = 0; i < argParse->commands_len; i++) { | ||||||
|  |         Command *command = argParse->commands[i]; | ||||||
|  |  | ||||||
|  |         __catStr(&help_msg, | ||||||
|  |                  4, | ||||||
|  |                  "\n  \033[1;32m", | ||||||
|  |                  command->name, | ||||||
|  |                  "\033[0m  ", | ||||||
|  |                  command->help); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (argParse->global_args_len > 0) { | ||||||
|  |         __catStr(&help_msg, 1, "\n\n\033[1;34mGlobal Options\033[0m:"); | ||||||
|  |         for (int i = 0; i < argParse->global_args_len; i++) { | ||||||
|  |             CommandArgs *arg = argParse->global_args[i]; | ||||||
|  |  | ||||||
|  |             __catStr(&help_msg, | ||||||
|  |                      6, | ||||||
|  |                      "\n  \033[1;32m", | ||||||
|  |                      arg->short_opt, | ||||||
|  |                      "\033[0m , \033[1;32m", | ||||||
|  |                      arg->long_opt, | ||||||
|  |                      "\033[0m  ", | ||||||
|  |                      arg->help); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return help_msg; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | _Noreturn void argParseHelp(ArgParse *argParse) { | ||||||
|  |     char *help_msg = argParseGenerateHelp(argParse); | ||||||
|  |     printf("%s\n", help_msg); | ||||||
|  |     free(help_msg); | ||||||
|  |     exit(0); | ||||||
|  | } | ||||||
							
								
								
									
										245
									
								
								src/ArgParseTools.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								src/ArgParseTools.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,245 @@ | |||||||
|  | #include "ArgParseTools.h" | ||||||
|  | #include "ArgParse.h" | ||||||
|  | #include <stddef.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 分配新内存复制字符串 | ||||||
|  |  * @param str 字符串 | ||||||
|  |  * @return 复制后的字符串内存指针 | ||||||
|  |  */ | ||||||
|  | char *stringNewCopy(char *str) { | ||||||
|  |     if (str == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     char *mem = malloc(strlen(str) + 1); | ||||||
|  |     if (mem == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     strcpy(mem, str); | ||||||
|  |     return mem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 构造命令 | ||||||
|  | Command *createCommand(char             *name, | ||||||
|  |                        char             *help, | ||||||
|  |                        char             *default_val, | ||||||
|  |                        ArgParseCallback  callback, | ||||||
|  |                        CommandGroup     *group, | ||||||
|  |                        ArgParseValueType value_typ) { | ||||||
|  |     // 构造命令结构 | ||||||
|  |     Command *command = malloc(sizeof(Command)); | ||||||
|  |     if (command == NULL || name == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     command->name = stringNewCopy(name); | ||||||
|  |     if (command->name == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     command->help             = stringNewCopy(help); | ||||||
|  |     command->default_val      = stringNewCopy(default_val); | ||||||
|  |     command->callback         = callback; | ||||||
|  |  | ||||||
|  |     command->sub_commands     = NULL; | ||||||
|  |     command->sub_commands_len = 0; | ||||||
|  |     command->args             = NULL; | ||||||
|  |     command->args_len         = 0; | ||||||
|  |     command->value_type       = value_typ; | ||||||
|  |  | ||||||
|  |     if (group != NULL) { | ||||||
|  |         command->group = group; | ||||||
|  |     } else { | ||||||
|  |         command->group = NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     command->val        = NULL; | ||||||
|  |     command->val_len    = 0; | ||||||
|  |     command->is_trigged = false; // 是否被触发 | ||||||
|  |     return command; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ArgType checkArgType(char *arg) { | ||||||
|  |     size_t len = strlen(arg); | ||||||
|  |     if (len == 0) { | ||||||
|  |         return BAD; | ||||||
|  |     } | ||||||
|  |     if (arg[0] == '-') { | ||||||
|  |         if (len >= 2) { | ||||||
|  |             if (arg[1] == '-') { | ||||||
|  |                 return LONG_ARG; | ||||||
|  |             } else { | ||||||
|  |                 return SHORT_ARG; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         return COMMAND; | ||||||
|  |     } | ||||||
|  |     return BAD; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 寻找命令 | ||||||
|  | Command *argParseFindCommand(ArgParse *argParse, char *name) { | ||||||
|  |     for (size_t i = 0; i < argParse->commands_len; i++) { | ||||||
|  |         if (strcmp(argParse->commands[i]->name, name) == 0) { | ||||||
|  |             return argParse->commands[i]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Command *argParseFindSubCommand(Command *command, char *name) { | ||||||
|  |     for (size_t i = 0; i < command->sub_commands_len; i++) { | ||||||
|  |         if (strcmp(command->sub_commands[i]->name, name) == 0) { | ||||||
|  |             return command->sub_commands[i]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CommandArgs *createCommandArgs(char             *short_opt, | ||||||
|  |                                char             *long_opt, | ||||||
|  |                                char             *default_val, | ||||||
|  |                                char             *help, | ||||||
|  |                                ArgParseCallback  callback, | ||||||
|  |                                bool              required, | ||||||
|  |                                ArgParseValueType value_type) { | ||||||
|  |     CommandArgs *args = malloc(sizeof(CommandArgs)); | ||||||
|  |  | ||||||
|  |     if (short_opt == NULL && long_opt == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // 分配内存 | ||||||
|  |     args->short_opt   = stringNewCopy(short_opt); | ||||||
|  |     args->long_opt    = stringNewCopy(long_opt); | ||||||
|  |     args->default_val = stringNewCopy(default_val); | ||||||
|  |     args->help        = stringNewCopy(help); | ||||||
|  |  | ||||||
|  |     args->callback    = callback; | ||||||
|  |     args->required    = required; | ||||||
|  |     args->value_type  = value_type; | ||||||
|  |  | ||||||
|  |     // 解析属性初始化 | ||||||
|  |     args->val         = NULL; | ||||||
|  |     args->val_len     = 0; | ||||||
|  |     args->is_trigged  = false; // 是否被触发 | ||||||
|  |  | ||||||
|  |     return args; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CommandArgs * | ||||||
|  | argParseFindCommandArgs(Command *command, char *name, bool short_flag) { | ||||||
|  |     if (command == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < command->args_len; i++) { | ||||||
|  |         if (short_flag) { | ||||||
|  |             if (command->args[i]->short_opt != NULL && | ||||||
|  |                 strcmp(command->args[i]->short_opt, name) == 0) { | ||||||
|  |                 return command->args[i]; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             if (command->args[i]->long_opt != NULL && | ||||||
|  |                 strcmp(command->args[i]->long_opt, name) == 0) { | ||||||
|  |                 return command->args[i]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CommandArgs * | ||||||
|  | argParseFindGlobalArgs(ArgParse *argParse, char *name, bool short_flag) { | ||||||
|  |     for (size_t i = 0; i < argParse->global_args_len; i++) { | ||||||
|  |         if (short_flag) { | ||||||
|  |             if (argParse->global_args[i]->short_opt != NULL && | ||||||
|  |                 strcmp(argParse->global_args[i]->short_opt, name) == 0) { | ||||||
|  |                 return argParse->global_args[i]; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             if (argParse->global_args[i]->long_opt != NULL && | ||||||
|  |                 strcmp(argParse->global_args[i]->long_opt, name) == 0) { | ||||||
|  |                 return argParse->global_args[i]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 设置命令参数值 | ||||||
|  |  * @param args 参数 | ||||||
|  |  * @param val 值 | ||||||
|  |  * @return 成功返回true,失败返回false | ||||||
|  |  */ | ||||||
|  | bool argParseSetArgVal(CommandArgs *args, char *val) { | ||||||
|  |     if (args->value_type == MULTIVALUE) { // 多值 | ||||||
|  |         args->val = realloc(args->val, (args->val_len + 1) * sizeof(char *)); | ||||||
|  |         if (args->val == NULL) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         args->val[args->val_len] = stringNewCopy(val); | ||||||
|  |         if (args->val[args->val_len] == NULL) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         args->val_len++; | ||||||
|  |         return true; | ||||||
|  |     } else if (args->value_type == SINGLEVALUE) { // 单值 | ||||||
|  |         if (args->val != NULL) { | ||||||
|  |             free(args->val); | ||||||
|  |         } | ||||||
|  |         args->val = malloc(sizeof(char *)); | ||||||
|  |  | ||||||
|  |         if (args->val == NULL) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         args->val[0] = stringNewCopy(val); // 分配内存 | ||||||
|  |         if (args->val[0] == NULL) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         args->val_len = 1; | ||||||
|  |         return true; | ||||||
|  |     } else if (args->value_type == NOVALUE) { // 无值 | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool argParseSetCommandVal(Command *command, char *val) { | ||||||
|  |     if (command->value_type == MULTIVALUE) { // 多值 | ||||||
|  |         command->val = | ||||||
|  |             realloc(command->val, (command->val_len + 1) * sizeof(char *)); | ||||||
|  |         if (command->val == NULL) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         command->val[command->val_len] = stringNewCopy(val); | ||||||
|  |         if (command->val[command->val_len] == NULL) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         command->val_len++; | ||||||
|  |         return true; | ||||||
|  |     } else if (command->value_type == SINGLEVALUE) { // 单值 | ||||||
|  |         if (command->val != NULL) { | ||||||
|  |             free(command->val); | ||||||
|  |         } | ||||||
|  |         command->val = malloc(sizeof(char *)); | ||||||
|  |  | ||||||
|  |         if (command->val == NULL) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         command->val[0] = stringNewCopy(val); // 分配内存 | ||||||
|  |         if (command->val[0] == NULL) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         command->val_len = 1; | ||||||
|  |         return true; | ||||||
|  |     } else if (command->value_type == NOVALUE) { // 无值 | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
							
								
								
									
										67
									
								
								src/ArgParseTools.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/ArgParseTools.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | #ifndef ARGPARSETOOLS_H | ||||||
|  | #define ARGPARSETOOLS_H | ||||||
|  |  | ||||||
|  | #include "ArgParse.h" | ||||||
|  | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     LONG_ARG,  // 长选项 | ||||||
|  |     SHORT_ARG, // 短选项 | ||||||
|  |     COMMAND,   // 命令 | ||||||
|  |     BAD,       // 错误 | ||||||
|  | } ArgType; | ||||||
|  |  | ||||||
|  | Command *createCommand(char             *name, | ||||||
|  |                        char             *help, | ||||||
|  |                        char             *default_val, | ||||||
|  |                        ArgParseCallback  callback, | ||||||
|  |                        CommandGroup     *group, | ||||||
|  |                        ArgParseValueType value_type); // 创建命令 | ||||||
|  |  | ||||||
|  | CommandGroup *createCommandGroup(char *name, char *help); // 创建命令组 | ||||||
|  |  | ||||||
|  | CommandGroup *addCommandToGroup(CommandGroup *group, | ||||||
|  |                                 Command *command); // 添加命令到命令组 | ||||||
|  |  | ||||||
|  | CommandArgs *createCommandArgs(char            *short_opt, | ||||||
|  |                                char            *long_opt, | ||||||
|  |                                char            *default_val, | ||||||
|  |                                char            *help, | ||||||
|  |                                ArgParseCallback callback, | ||||||
|  |                                bool             required, | ||||||
|  |                                ArgParseValueType value_type); // 创建命令参数 | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 设置命令参数值 | ||||||
|  |  * @param args 参数 | ||||||
|  |  * @param val 值 | ||||||
|  |  * @return 成功返回true,失败返回false | ||||||
|  |  */ | ||||||
|  | bool argParseSetArgVal(CommandArgs *args, char *val); // 设置命令参数值 | ||||||
|  |  | ||||||
|  | bool argParseSetCommandVal(Command *command, char *val); // 设置命令值 | ||||||
|  |  | ||||||
|  | ArgType checkArgType(char *arg); // 检查参数类型 | ||||||
|  |  | ||||||
|  | Command *argParseFindCommand(ArgParse *argParse, char *name); // 查找命令 | ||||||
|  |  | ||||||
|  | Command *argParseFindSubCommand(Command *command, char *name); // 查找子命令 | ||||||
|  |  | ||||||
|  | CommandArgs *argParseFindCommandArgs(Command *command, | ||||||
|  |                                      char    *name, | ||||||
|  |                                      bool     short_flag); // 查找命令参数 | ||||||
|  |  | ||||||
|  | CommandArgs *argParseFindGlobalArgs(ArgParse *argParse, | ||||||
|  |                                     char     *name, | ||||||
|  |                                     bool      short_flag); // 查找全局参数 | ||||||
|  |  | ||||||
|  | char *stringNewCopy(char *str); // 创建字符串副本 | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif // __cplusplus | ||||||
|  | #endif // ARGPARSETOOLS_H | ||||||
							
								
								
									
										34
									
								
								tests/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								tests/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | project(CArgParseTest_) | ||||||
|  |  | ||||||
|  | #单命令的单一选项多值测试 | ||||||
|  | add_executable(${PROJECT_NAME}single_arg test_single_arg.c) | ||||||
|  | target_link_libraries(${PROJECT_NAME}single_arg CArgParse) | ||||||
|  | add_test(${PROJECT_NAME}single_arg ${PROJECT_NAME}single_arg install -p testpackge1 testpackge2 testpackge3) | ||||||
|  |  | ||||||
|  | # 单命令的多选项测试 | ||||||
|  | add_executable(${PROJECT_NAME}mult_arg test_mult_arg.c) | ||||||
|  | target_link_libraries(${PROJECT_NAME}mult_arg CArgParse) | ||||||
|  | add_test(${PROJECT_NAME}mult_arg ${PROJECT_NAME}mult_arg install -p testpackge1 testpackge2 testpackge3 -i www.test.com -f file1.txt file2.txt) | ||||||
|  |  | ||||||
|  | # 全局选项测试 | ||||||
|  | add_executable(${PROJECT_NAME}global_arg test_global_arg.c) | ||||||
|  | target_link_libraries(${PROJECT_NAME}global_arg CArgParse) | ||||||
|  | add_test(${PROJECT_NAME}global_arg ${PROJECT_NAME}global_arg -v install -p testpackge1 testpackge2 testpackge3 -q) | ||||||
|  |  | ||||||
|  | # 子命令测试 | ||||||
|  | add_executable(${PROJECT_NAME}subcommand test_subcommand.c) | ||||||
|  | target_link_libraries(${PROJECT_NAME}subcommand CArgParse) | ||||||
|  | add_test(${PROJECT_NAME}subcommand ${PROJECT_NAME}subcommand -v install tools -t tool1 tool2) | ||||||
|  |  | ||||||
|  | # 未知命令测试 | ||||||
|  | add_executable(${PROJECT_NAME}unknow_command test_unknow_command.c) | ||||||
|  | target_link_libraries(${PROJECT_NAME}unknow_command CArgParse) | ||||||
|  | add_test(${PROJECT_NAME}unknow_command ${PROJECT_NAME}unknow_command unknow) | ||||||
|  | set_tests_properties(${PROJECT_NAME}unknow_command PROPERTIES WILL_FAIL TRUE) | ||||||
|  | set_tests_properties(${PROJECT_NAME}unknow_command PROPERTIES FAIL_REGULAR_EXPRESSION "ERROR: Last command is not found") | ||||||
|  |  | ||||||
|  | # 未知命令选项测试,预期打印该命令的帮助信息 | ||||||
|  | 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) | ||||||
							
								
								
									
										91
									
								
								tests/initArgParse.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								tests/initArgParse.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | |||||||
|  | #include "ArgParse.h" | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | ArgParse *initArgParse() { | ||||||
|  |     ArgParse *argparse    = argParseInit("测试程序"); | ||||||
|  |     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; | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								tests/test_global_arg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								tests/test_global_arg.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | #include "ArgParse.h" | ||||||
|  | #include "initArgParse.h" | ||||||
|  | #include <assert.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) { | ||||||
|  |     ArgParse *argparse = initArgParse(); | ||||||
|  |  | ||||||
|  |     argParseParse(argparse, argc, argv); | ||||||
|  |  | ||||||
|  |     char *val = argParseGetGlobalArg(argparse, "-v"); | ||||||
|  |  | ||||||
|  |     if (argParseCheckGlobalTriggered(argparse, "-v")) { | ||||||
|  |         printf("Global arg -v triggered\n"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (val != NULL) { | ||||||
|  |         printf("Global arg -v: %s\n", val); | ||||||
|  |     } else { | ||||||
|  |         printf("Global arg -v is NULL\n"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     char *val_q = argParseGetGlobalArg(argparse, "-q"); | ||||||
|  |  | ||||||
|  |     if (argParseCheckGlobalTriggered(argparse, "-q")) { | ||||||
|  |         printf("Global arg -q triggered\n"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (val != NULL) { | ||||||
|  |         printf("Global arg -q: %s\n", val); | ||||||
|  |     } else { | ||||||
|  |         printf("Global arg -q is NULL\n"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     argParseFree(argparse); | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								tests/test_mult_arg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								tests/test_mult_arg.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | #include "ArgParse.h" | ||||||
|  | #include "initArgParse.h" | ||||||
|  | #include <assert.h> | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) { | ||||||
|  |     ArgParse *argparse = initArgParse(); | ||||||
|  |  | ||||||
|  |     argParseParse(argparse, argc, argv); | ||||||
|  |  | ||||||
|  |     const char *testv[3] = {"testpackge1", "testpackge2", "testpackge3"}; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // Test -p | ||||||
|  |     char *val = argParseGetCurArg(argparse, "-p"); | ||||||
|  |  | ||||||
|  |     int len = 0; | ||||||
|  |     char **vals = argParseGetCurArgList(argparse, "-p", &len); | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < len; i++) { | ||||||
|  |         printf("-p Value: %s\n", vals[i]); | ||||||
|  |         assert(strcmp(vals[i], testv[i]) == 0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Test -i | ||||||
|  |     char *val_i = argParseGetCurArg(argparse, "-i"); | ||||||
|  |     printf("-i Value: %s\n", val_i); | ||||||
|  |     assert(strcmp(val_i, "www.test.com") == 0); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // Test -f | ||||||
|  |     len = 0; | ||||||
|  |     const char *testf[2] = {"file1.txt", "file2.txt"}; | ||||||
|  |     char **val_f = argParseGetCurArgList(argparse, "-f", &len); | ||||||
|  |     for (int i = 0; i < len; i++) { | ||||||
|  |         printf("-f Value: %s\n", val_f[i]); | ||||||
|  |         assert(strcmp(val_f[i], testf[i]) == 0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     argParseFree(argparse); | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								tests/test_single_arg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								tests/test_single_arg.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | #include "ArgParse.h" | ||||||
|  | #include "initArgParse.h" | ||||||
|  | #include <assert.h> | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) { | ||||||
|  |     ArgParse *argparse = initArgParse(); | ||||||
|  |  | ||||||
|  |     argParseParse(argparse, argc, argv); | ||||||
|  |  | ||||||
|  |     const char *testv[3] = {"testpackge1", "testpackge2", "testpackge3"}; | ||||||
|  |  | ||||||
|  |     char *val = argParseGetCurArg(argparse, "-p"); | ||||||
|  |  | ||||||
|  |     int len = 0; | ||||||
|  |     char **vals = argParseGetCurArgList(argparse, "-p", &len); | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < len; i++) { | ||||||
|  |         printf("-p Value: %s\n", vals[i]); | ||||||
|  |         assert(strcmp(vals[i], testv[i]) == 0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     argParseFree(argparse); | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								tests/test_subcommand.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/test_subcommand.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | #include "ArgParse.h" | ||||||
|  | #include "initArgParse.h" | ||||||
|  | #include <assert.h> | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) { | ||||||
|  |     ArgParse *argparse = initArgParse(); | ||||||
|  |  | ||||||
|  |     argParseParse(argparse, argc, argv); | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     char *command_name = argParseGetCurCommandName(argparse); | ||||||
|  |     printf("command name: %s\n", command_name); | ||||||
|  |     assert(strcmp(command_name, "tools") == 0); | ||||||
|  |  | ||||||
|  |     char * val = argParseGetCurArg(argparse, "-t"); | ||||||
|  |     printf("tools -t: %s\n", val); | ||||||
|  |  | ||||||
|  |     argParseFree(argparse); | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								tests/test_unknow_command.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tests/test_unknow_command.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | #include "ArgParse.h" | ||||||
|  | #include "initArgParse.h" | ||||||
|  | #include <assert.h> | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) { | ||||||
|  |     ArgParse *argparse = initArgParse(); | ||||||
|  |  | ||||||
|  |     argParseParse(argparse, argc, argv); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     argParseFree(argparse); | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										206
									
								
								uv.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								uv.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,206 @@ | |||||||
|  | version = 1 | ||||||
|  | revision = 2 | ||||||
|  | requires-python = ">=3.13" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "cargparse" | ||||||
|  | version = "0.1.0" | ||||||
|  | source = { virtual = "." } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "conan" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [package.metadata] | ||||||
|  | requires-dist = [{ name = "conan", specifier = ">=2.18.1" }] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "certifi" | ||||||
|  | version = "2025.7.9" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/de/8a/c729b6b60c66a38f590c4e774decc4b2ec7b0576be8f1aa984a53ffa812a/certifi-2025.7.9.tar.gz", hash = "sha256:c1d2ec05395148ee10cf672ffc28cd37ea0ab0d99f9cc74c43e588cbd111b079", size = 160386, upload-time = "2025-07-09T02:13:58.874Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/66/f3/80a3f974c8b535d394ff960a11ac20368e06b736da395b551a49ce950cce/certifi-2025.7.9-py3-none-any.whl", hash = "sha256:d842783a14f8fdd646895ac26f719a061408834473cfc10203f6a575beb15d39", size = 159230, upload-time = "2025-07-09T02:13:57.007Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "charset-normalizer" | ||||||
|  | version = "3.4.2" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "colorama" | ||||||
|  | version = "0.4.6" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "conan" | ||||||
|  | version = "2.18.1" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "colorama" }, | ||||||
|  |     { name = "distro", marker = "platform_system == 'FreeBSD' or sys_platform == 'linux'" }, | ||||||
|  |     { name = "fasteners" }, | ||||||
|  |     { name = "jinja2" }, | ||||||
|  |     { name = "patch-ng" }, | ||||||
|  |     { name = "python-dateutil" }, | ||||||
|  |     { name = "pyyaml" }, | ||||||
|  |     { name = "requests" }, | ||||||
|  |     { name = "urllib3" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/c7/55/9a10f21dd6dc9137c6e7b51eff7c54ab92400812e6e795d1a991ead00b54/conan-2.18.1.tar.gz", hash = "sha256:5d8e9fac7614de9297933f65de8f17db14851a871cebc962f4856b7c294f43c5", size = 521034, upload-time = "2025-07-04T07:08:07.842Z" } | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "distro" | ||||||
|  | version = "1.8.0" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/4b/89/eaa3a3587ebf8bed93e45aa79be8c2af77d50790d15b53f6dfc85b57f398/distro-1.8.0.tar.gz", hash = "sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8", size = 59428, upload-time = "2022-10-10T15:30:33.395Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/f4/2c/c90a3adaf0ddb70afe193f5ebfb539612af57cffe677c3126be533df3098/distro-1.8.0-py3-none-any.whl", hash = "sha256:99522ca3e365cac527b44bde033f64c6945d90eb9f769703caaec52b09bbd3ff", size = 20315, upload-time = "2022-10-10T15:30:26.903Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "fasteners" | ||||||
|  | version = "0.19" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/5f/d4/e834d929be54bfadb1f3e3b931c38e956aaa3b235a46a3c764c26c774902/fasteners-0.19.tar.gz", hash = "sha256:b4f37c3ac52d8a445af3a66bce57b33b5e90b97c696b7b984f530cf8f0ded09c" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/61/bf/fd60001b3abc5222d8eaa4a204cd8c0ae78e75adc688f33ce4bf25b7fafa/fasteners-0.19-py3-none-any.whl", hash = "sha256:758819cb5d94cdedf4e836988b74de396ceacb8e2794d21f82d131fd9ee77237" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "idna" | ||||||
|  | version = "3.10" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "jinja2" | ||||||
|  | version = "3.1.6" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "markupsafe" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "markupsafe" | ||||||
|  | version = "3.0.2" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "patch-ng" | ||||||
|  | version = "1.18.1" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ee/c0/53a2f017ac5b5397a7064c2654b73c3334ac8461315707cbede6c12199eb/patch-ng-1.18.1.tar.gz", hash = "sha256:52fd46ee46f6c8667692682c1fd7134edc65a2d2d084ebec1d295a6087fc0291", size = 17913, upload-time = "2024-10-25T12:20:10.591Z" } | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "python-dateutil" | ||||||
|  | version = "2.9.0.post0" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "six" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "pyyaml" | ||||||
|  | version = "6.0.2" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "requests" | ||||||
|  | version = "2.32.4" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "certifi" }, | ||||||
|  |     { name = "charset-normalizer" }, | ||||||
|  |     { name = "idna" }, | ||||||
|  |     { name = "urllib3" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "six" | ||||||
|  | version = "1.17.0" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "urllib3" | ||||||
|  | version = "2.0.7" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/af/47/b215df9f71b4fdba1025fc05a77db2ad243fa0926755a52c5e71659f4e3c/urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84", size = 282546, upload-time = "2023-10-17T17:46:50.542Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d2/b2/b157855192a68541a91ba7b2bbcb91f1b4faa51f8bae38d8005c034be524/urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e", size = 124213, upload-time = "2023-10-17T17:46:48.538Z" }, | ||||||
|  | ] | ||||||
		Reference in New Issue
	
	Block a user