Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add argc to struct optparse #7

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions example/optparse_demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ int optparse_short_test(int argc, char **argv)
int ch;
struct optparse options;

optparse_init(&options, argv);
optparse_init(&options, argc, argv);
while((ch = optparse(&options, "ab:c::")) != -1)
{
ch = ch;
Expand Down Expand Up @@ -36,7 +36,7 @@ int optparse_long_test(int argc, char **argv)
int option_index;
struct optparse options;

optparse_init(&options, argv);
optparse_init(&options, argc, argv);
while((ch = optparse_long(&options, long_opts, &option_index)) != -1)
{
ch = ch;
Expand Down
5 changes: 3 additions & 2 deletions optparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,9 @@ static int optparse_long_fallback(struct optparse *options,
return result;
}

void optparse_init(struct optparse *options, char **argv)
void optparse_init(struct optparse *options, int argc, char **argv)
{
options->argc = argc;
options->argv = argv;
options->permute = 1;
options->optind = argv[0] != 0;
Expand All @@ -153,7 +154,7 @@ int optparse(struct optparse *options, const char *optstring)
options->errmsg[0] = '\0';
options->optopt = 0;
options->optarg = 0;
if (option == 0)
if ((options->optind>= options->argc) || option == 0)
{
return -1;
}
Expand Down
3 changes: 2 additions & 1 deletion optparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

struct optparse
{
int argc;
char **argv;
int permute;
int optind;
Expand All @@ -42,7 +43,7 @@ struct optparse_long
/**
* Initializes the parser state.
*/
void optparse_init(struct optparse *options, char **argv);
void optparse_init(struct optparse *options, int argc, char **argv);

/**
* Read the next option in the argv array.
Expand Down
34 changes: 17 additions & 17 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
# optparse #

optparse是一个开源, 可移植的, 可重入的和可嵌入的类getopt命令行参数解析器. 它支持POSIX getopt选项字符串, GNU风格的长参数解析, 参数置换和子命令处理.
optparse是一个开源, 可移植的, 可重入的和可嵌入的类getopt命令行参数解析器. 它支持POSIX getopt选项字符串, GNU风格的长参数解析, 参数置换和子命令处理.

## 1. 为什么不在RTT下直接使用getopt函数?

POSIX getopt解析器有三个致命的缺陷. 这些缺陷都是可以通过optparse来解决的:
POSIX getopt解析器有三个致命的缺陷. 这些缺陷都是可以通过optparse来解决的:

1. getopt的解析状态存储在全局变量中, 其中一些变量是静态不可访问的. 这意味着在RTT(RT-Thread)下只能有一个msh命令可以使用getopt, 其他msh命令再次使用getopt会出现bug. 而optparse将每次解析的状态存储在一个属于msh的私有结构体中, 每一个optparse命令解析器不会相互影响.
1. getopt的解析状态存储在全局变量中, 其中一些变量是静态不可访问的. 这意味着在RTT(RT-Thread)下只能有一个msh命令可以使用getopt, 其他msh命令再次使用getopt会出现bug. 而optparse将每次解析的状态存储在一个属于msh的私有结构体中, 每一个optparse命令解析器不会相互影响.

2. 在RTT中BSP一般支持Keil, IAR和GCC, 对于keil环境下是无法支持原生的POSIX getopt解析器, 这样就造成了在RTT下实现命令解析是无法移植到Keil中使用的, 代码的兼容性降低!

3. 在getopt中, 错误消息被打印到stderr. 使用opterr可以禁用此功能, 但消息本身仍然不可访问. optparse通过将错误消息写入它的errmsg字段来解决这个问题, 该字段可以被打印到任何地方. optparse的缺点是, 这个错误消息总是用英语而不是当前语言环境.
3. 在getopt中, 错误消息被打印到stderr. 使用opterr可以禁用此功能, 但消息本身仍然不可访问. optparse通过将错误消息写入它的errmsg字段来解决这个问题, 该字段可以被打印到任何地方. optparse的缺点是, 这个错误消息总是用英语而不是当前语言环境.

## 2. 命令顺序

默认情况下, argv在被解析时会将非选项的参数移动到数组的末尾. 可以通过在初始化后将`permute`字段设置为0来禁用它.
默认情况下, argv在被解析时会将非选项的参数移动到数组的末尾. 可以通过在初始化后将`permute`字段设置为0来禁用它.

~~~c
struct optparse options;
optparse_init(&options, argv);
optparse_init(&options, argc, argv);
options.permute = 0;
~~~

## 3. 对比

optparse的接口应该是任何熟悉getopt的人都熟悉的. 选项字符串具有相同的格式, 解析器结构体成员变量与getopt全局变量(optarg、optind、optopt)具有相同的名称.
optparse的接口应该是任何熟悉getopt的人都熟悉的. 选项字符串具有相同的格式, 解析器结构体成员变量与getopt全局变量(optarg、optind、optopt)具有相同的名称.

long选项解析器`optparse_long()`API与GNU的`getopt_long()`非常相似,可以作为替代api.
long选项解析器`optparse_long()`API与GNU的`getopt_long()`非常相似,可以作为替代api.

optparse没有分配内存. 此外optparse没有依赖项, 包括libc本身. 因此可以在标准C库无法使用的情况下使用.
optparse没有分配内存. 此外optparse没有依赖项, 包括libc本身. 因此可以在标准C库无法使用的情况下使用.

查看`optparse.h`文件可以了解完整的API.
查看`optparse.h`文件可以了解完整的API.

## 4. 示例使用

这是一个通用的getopt命令解析代码:
这是一个通用的getopt命令解析代码:

~~~c
#include <stdio.h>
Expand Down Expand Up @@ -76,7 +76,7 @@ int main(int argc, char **argv)
}
~~~

如果使用optparse在RTT下解析, 同样的功能将使用如下的代码的实现:
如果使用optparse在RTT下解析, 同样的功能将使用如下的代码的实现:

~~~c
#include <stdio.h>
Expand All @@ -95,7 +95,7 @@ int cmd_parse(int argc, char **argv)
int option;
struct optparse options;

optparse_init(&options, argv);
optparse_init(&options, argc, argv);
while ((option = optparse(&options, "abc:d::")) != -1) {
switch (option) {
case 'a':
Expand Down Expand Up @@ -124,7 +124,7 @@ int cmd_parse(int argc, char **argv)
MSH_CMD_EXPORT(cmd_parse, cmd description);
~~~

这是optparse对长选项参数的支持:
这是optparse对长选项参数的支持:

~~~c
#include <stdio.h>
Expand All @@ -151,7 +151,7 @@ int main(int argc, char **argv)
int option;
struct optparse options;

optparse_init(&options, argv);
optparse_init(&options, argc, argv);
while ((option = optparse_long(&options, longopts, NULL)) != -1) {
switch (option) {
case 'a':
Expand Down Expand Up @@ -182,5 +182,5 @@ int main(int argc, char **argv)

## 5. 感谢

1. 该库移植于https://github.com/skeeto/optparse.
2. 感谢skeeto. 本移植是修改了部分原作者的代码针对RTT在线包实现的版本, 该仓库保留原作者的许可声明! 具体原作者许可请查看https://github.com/skeeto/optparse/blob/master/UNLICENSE.
1. 该库移植于https://github.com/skeeto/optparse.
2. 感谢skeeto. 本移植是修改了部分原作者的代码针对RTT在线包实现的版本, 该仓库保留原作者的许可声明! 具体原作者许可请查看https://github.com/skeeto/optparse/blob/master/UNLICENSE.