一.busybox中的getopt32
1. 说明
a. 当命令行中调用./_install/busybox arping -I eth2 -s 192.168.4.68 192.168.4.1
参数: -I eth2 -s 192.168.4.68 192.168.4.1
参数字符串: "DUAqfbc:w:I:s:"
b. opt = getopt32(argv, "DUAqfbc:w:I:s:", &count, &str_timeout, &device, &source);
dbmsg("count=%d,str_timeout=%s,device=%s,source=%s",count,str_timeout, device,source);
关于getopt32,假设命令如下:
sudo ./_install/busybox arping -I eth2 -s 192.168.4.68 192.168.4.1 -w 10 -f
count=-1,str_timeout=10,device=eth2,source=192.168.4.68
调用了getopt32之后,为什么count, str_timeout, device, source就会各自保存正确的参数呢?
2.代码
-
uint32_t FAST_FUNC
-
getopt32(char **argv, const char *applet_opts, ...)
-
{
-
int argc;
-
unsigned flags = 0;
-
unsigned requires = 0;
-
t_complementary complementary[33]; /* last stays zero-filled */
-
char first_char;
-
int c;
-
const unsigned char *s;
-
t_complementary *on_off;
-
va_list p;
-
const struct option *l_o;
-
struct option *long_options = (struct option *) &bb_null_long_options;
-
unsigned trigger;
-
char **pargv;
-
int min_arg = 0;
-
int max_arg = -1;
-
-
#define SHOW_USAGE_IF_ERROR 1
-
#define ALL_ARGV_IS_OPTS 2
-
#define FIRST_ARGV_IS_OPT 4
-
-
int spec_flgs = 0;
-
-
//a.统计命令行中参数的个数
-
argc = 1;
-
while (argv[argc])
-
argc++;
-
va_start(p, applet_opts);
-
-
c = 0;
-
on_off = complementary;
-
memset(on_off, 0, sizeof(complementary));
-
-
/* skip bbox extension */
-
first_char = applet_opts[0];
-
if (first_char == '!')
-
applet_opts++;
-
-
//s指向参数字符串"DUAqfbc:w:I:s:"中的首地址D
-
s = (const unsigned char *)applet_opts; //跳过首地址是+或-的字符
-
if (*s == '+' || *s == '-')
-
s++;
-
//b.解析参数字符串"DUAqfbc:w:I:s:"
-
//将参数存在opt_char中,switch_on的每一位代表一个参数
-
while (*s) {
-
if (c >= 32)
-
break;
-
on_off->opt_char = *s;
-
on_off->switch_on = (1 << c);
-
if (*++s == ':') { //遇到:说明后面需要带一个参数
-
on_off->optarg = va_arg(p, void **); //用on_off指向参数字符串
-
while (*++s == ':')
-
continue;
-
}
-
on_off++;
-
c++;
-
}
-
//因为没有在arping.c中设定applet_long_options,所以applet_long_options=NULL
-
if (applet_long_options) {
-
... //此处跳过
-
}
-
-
for (s = (const unsigned char *)opt_complementary; s && *s; s++) {
-
//解析可选参数,看了半天没看明白,放弃了
-
}
-
opt_complementary = NULL;
-
va_end(p);
-
-
optind = 0;
-
while ((c = getopt(argc, argv, applet_opts)) != -1) {
-
c &= 0xff; /* fight libc's sign extension */
-
for (on_off = complementary; on_off->opt_char != c; on_off++) {
-
if (on_off->opt_char == '\0' ) {
-
goto error;
-
}
-
}
-
if (flags & on_off->incongruously)
-
goto error;
-
trigger = on_off->switch_on & on_off->switch_off;
-
flags &= ~(on_off->switch_off ^ trigger);
-
flags |= on_off->switch_on ^ trigger;
-
flags ^= trigger;
-
if (on_off->counter)
-
(*(on_off->counter))++;
-
if (optarg) {
-
if (on_off->param_type == PARAM_LIST) {
-
llist_add_to_end((llist_t **)(on_off->optarg), optarg);
-
} else if (on_off->param_type == PARAM_INT) {
-
*(unsigned*)(on_off->optarg) = xatoi_positive(optarg);
-
} else if (on_off->optarg) { //都是string类型,就把optarg赋给on_off->optarg就是了
-
*(char **)(on_off->optarg) = optarg;
-
}
-
}
-
}
-
-
/* check depending requires for given options */
-
for (on_off = complementary; on_off->opt_char; on_off++) {
-
if (on_off->requires
-
&& (flags & on_off->switch_on)
-
&& (flags & on_off->requires) == 0
-
) {
-
goto error;
-
}
-
}
-
if (requires && (flags & requires) == 0)
-
goto error;
-
argc -= optind;
-
if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
-
goto error;
-
-
option_mask32 = flags;
-
return flags;
-
-
error:
-
if (first_char != '!')
-
bb_show_usage();
-
return (int32_t)-1;
-
}
3.
-
typedef struct {
-
unsigned char opt_char;
-
smallint param_type;
-
unsigned switch_on;
-
unsigned switch_off;
-
unsigned incongruously;
-
unsigned requires;
-
void **optarg;
-
int *counter;
-
} t_complementary;
全局结构体complementary数组complementary[33];
其中每个opt_char指向参数字符串中的一个参数:即每一个指向 D U A q f b c w I s中的一个
其中每个switch_on: D(1<<0) U(1<<1) A(1<<2)
"DUAqfbc:w:I:s:"
opt_complementary = "=1:Df:AU:c+";
解析opt_complementary
a. 跳过其中的:
b. 检查参数中的 ? - = 这三个符号后面必须跟个数字
c.
opt = getopt32(argv, "DUAqfbc:w:I:s:", &count, &str_timeout, &device, &source);
这儿知道意思了,不看了,就这样了!写点代码验证一下得了,不看了!
二. 简短点
2.1 自己写个demo
-
#include <unistd.h>
-
#include <stdarg.h>
-
int getopt32(int argc, char** argv, char* opts, ...)
-
{
-
int i=0, ret;
-
va_list p;
-
char *s;
-
void **my_arg[1024];
-
-
va_start(p, opts);
-
-
s=opts; //s
-
while(*s++)
-
{
-
if(*s != ':')
-
continue;
-
//找到两个参数cc与buf的地址,保存到my_arg数组中
-
my_arg[i++] = va_arg(p, void**);
-
}
-
-
i=0;
-
while((ret=getopt(argc, argv, opts)) != -1)
-
{
-
if(optarg == NULL)
-
continue;
-
dbmsg("optarg=%s, strlen(optarg)=%d", optarg, strlen(optarg));
-
//*(char **)(my_arg)[i] = optarg;
-
memcpy((char **)(my_arg)[i], optarg, strlen(optarg)); //将从命令行传来的参数解析,并写到c与buf中
-
dbmsg("addr=0x%x", (char **)(my_arg)[i]);
-
dbmsg("%s", (char **)(my_arg)[i]);
-
i++;
-
}
-
}
-
-
int main ( int argc, char *argv[] )
-
{
-
char c[1024];
-
char buf[1024];
-
dbmsg("addr c=0x%x,buf=0x%x", c, buf); //打印一下c与buf的地址
-
getopt32(argc, argv, "hc:s:", c, buf);
-
dbmsg("c=%s,buf=%s", c, buf); //打印c与buf的结果
-
return EXIT_SUCCESS;
-
}
现在这个原理就很明显了:
a. 找到可变参数的地址
b. 解析DUAqfbc:w:I:s:字符串,遇到:
2.2 运行结果:
-
cong@msi:/work/test/busytest/1varg$ ./varg -s 1 -c 2
-
varg.c:main[40]: addr c=0x5439390,s=0x5439790
-
varg.c:getopt32[27]: optarg=1, strlen(optarg)=1
-
varg.c:getopt32[30]: addr=0x5439390
-
varg.c:getopt32[31]: 1
-
varg.c:getopt32[27]: optarg=2, strlen(optarg)=1
-
varg.c:getopt32[30]: addr=0x5439790
-
varg.c:getopt32[31]: 2
-
varg.c:main[42]: c=1,s=2 //正确
-
-
cong@msi:/work/test/busytest/1varg$ ./varg -s 1
-
varg.c:main[40]: addr c=0x39c4ec70,s=0x39c4f070
-
varg.c:getopt32[27]: optarg=1, strlen(optarg)=1
-
varg.c:getopt32[30]: addr=0x39c4ec70
-
varg.c:getopt32[31]: 1
-
varg.c:main[42]: c=1,s= //不正确//这儿有个bug
-
-
cong@msi:/work/test/busytest/1varg$ ./varg -c 2
-
varg.c:main[40]: addr c=0x8fcdb0e0,s=0x8fcdb4e0
-
varg.c:getopt32[27]: optarg=2, strlen(optarg)=1
-
varg.c:getopt32[30]: addr=0x8fcdb0e0
-
varg.c:getopt32[31]: 2
-
varg.c:main[42]: c=2,s= //正确
这儿有个bug:不能区分参数,总是把第1个参数放在c中
所以对于
hc:s:,不提供c参数只提供s参数时,会有问题:将s的参数赋给了c,这样是不对的
2.3 代码
1varg.rar (下载后改名为1varg.tar.gz)
三. 改进
3.1改进后的代码
-
#include "utils.h"
-
#include <unistd.h>
-
#include <stdarg.h>
-
int getopt32(int argc, char** argv, char* opts, ...)
-
{
-
int i=0, ret,len=0; //len-->带:的参数的个数
-
va_list p;
-
char *s;
-
void **my_arg[1024];
-
char opt_char[1024];
-
-
va_start(p, opts);
-
-
s=opts; //s
-
while(*s++)
-
{
-
if(*s != ':')
-
continue;
-
//get args addr
-
my_arg[len] = va_arg(p, void**); //获取c与s的地址,即传给getopt32的可变参数的地址
-
opt_char[len] = *(s-1); //保存"hc:s:"中的c与s
-
len++;
-
}
-
-
while((ret=getopt(argc, argv, opts)) != -1)
-
{
-
if(optarg == NULL)
-
continue;
-
dbmsg("ret=%c,optarg=%s, strlen(optarg)=%d",ret, optarg, strlen(optarg));
-
for(i=0; i<len; i++)
-
{
-
if(opt_char[i] == ret) //比较<"hc:s:"中的c与s>与ret是否相同
-
{
-
//*(char **)(my_arg)[i] = optarg;
-
memcpy((char **)(my_arg)[i], optarg, strlen(optarg));
-
dbmsg("addr=0x%x", (char **)(my_arg)[i]);
-
dbmsg("%s", (char **)(my_arg)[i]);
-
}
-
}
-
}
-
}
-
-
int main ( int argc, char *argv[] )
-
{
-
char c[1024];
-
char s[1024];
-
dbmsg("addr c=0x%x,s=0x%x", c, s);
-
getopt32(argc, argv, "hc:s:", c, s);
-
dbmsg("c=%s,s=%s", c, s);
-
return EXIT_SUCCESS;
-
}
这个地方太不好说明了,都叫参数,没法区分,直接看代码吧!
3.2结果
-
cong@msi:/work/test/busytest/2varg$ ./varg -s 1 -c 2
-
varg.c:main[48]: addr c=0x59df07a0,s=0x59df0ba0
-
varg.c:getopt32[29]: ret=s,optarg=1, strlen(optarg)=1
-
varg.c:getopt32[37]: addr=0x59df0ba0
-
varg.c:getopt32[38]: 1
-
varg.c:getopt32[29]: ret=c,optarg=2, strlen(optarg)=1
-
varg.c:getopt32[37]: addr=0x59df07a0
-
varg.c:getopt32[38]: 2
-
varg.c:main[50]: c=2,s=1 //正确
-
-
cong@msi:/work/test/busytest/2varg$ ./varg -s 1
-
varg.c:main[48]: addr c=0x34bba3a0,s=0x34bba7a0
-
varg.c:getopt32[29]: ret=s,optarg=1, strlen(optarg)=1
-
varg.c:getopt32[37]: addr=0x34bba7a0
-
varg.c:getopt32[38]: 1
-
varg.c:main[50]: c=,s=1 //正确
-
-
cong@msi:/work/test/busytest/2varg$ ./varg -c 2
-
varg.c:main[48]: addr c=0xa3100400,s=0xa3100800
-
varg.c:getopt32[29]: ret=c,optarg=2, strlen(optarg)=1
-
varg.c:getopt32[37]: addr=0xa3100400
-
varg.c:getopt32[38]: 2
-
varg.c:main[50]: c=2,s= //正确
3.3 代码
2varg.rar (下载后改名为2varg.tar.gz)
阅读(3429) | 评论(1) | 转发(0) |