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