Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2150502
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2015-07-01 11:32:25

一.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.代码
  1. uint32_t FAST_FUNC
  2. getopt32(char **argv, const char *applet_opts, ...)
  3. {
  4.     int argc;
  5.     unsigned flags = 0;
  6.     unsigned requires = 0;
  7.     t_complementary complementary[33]; /* last stays zero-filled */
  8.     char first_char;
  9.     int c;
  10.     const unsigned char *s;
  11.     t_complementary *on_off;
  12.     va_list p;
  13.     const struct option *l_o;
  14.     struct option *long_options = (struct option *) &bb_null_long_options;
  15.     unsigned trigger;
  16.     char **pargv;
  17.     int min_arg = 0;
  18.     int max_arg = -1;

  19. #define SHOW_USAGE_IF_ERROR 1
  20. #define ALL_ARGV_IS_OPTS 2
  21. #define FIRST_ARGV_IS_OPT 4

  22.     int spec_flgs = 0;

  23.     //a.统计命令行中参数的个数
  24.     argc = 1;
  25.     while (argv[argc])
  26.         argc++;
  1.     va_start(p, applet_opts);

  2.     c = 0;
  3.     on_off = complementary;
  4.     memset(on_off, 0, sizeof(complementary));

  5.     /* skip bbox extension */
  6.     first_char = applet_opts[0];
  7.     if (first_char == '!')
  8.         applet_opts++;

  9.     //s指向参数字符串"DUAqfbc:w:I:s:"中的首地址D
  10.     s = (const unsigned char *)applet_opts;  //跳过首地址是+或-的字符
  11.     if (*s == '+' || *s == '-')
  12.         s++;
  13.     //b.解析参数字符串"DUAqfbc:w:I:s:"
  14.     //将参数存在opt_char中,switch_on的每一位代表一个参数   
  15.     while (*s) {
  16.         if (c >= 32)
  17.             break;
  18.         on_off->opt_char = *s;
  19.         on_off->switch_on = (1 << c);
  20.         if (*++s == ':') {                         //遇到:说明后面需要带一个参数
  21.             on_off->optarg = va_arg(p, void **);   //用on_off指向参数字符串
  22.             while (*++s == ':')
  23.                 continue;
  24.         }
  25.         on_off++;
  26.         c++;
  27.     }
  28.     //因为没有在arping.c中设定applet_long_options,所以applet_long_options=NULL
  29.     if (applet_long_options) {
  30.         ... //此处跳过
  31.     }

  32.     for (s = (const unsigned char *)opt_complementary; s && *s; s++) {
  33.         //解析可选参数,看了半天没看明白,放弃了
  34.     }
  35.     opt_complementary = NULL;
  36.     va_end(p);

  37.     optind = 0;
  38.     while ((c = getopt(argc, argv, applet_opts)) != -1) {
  39.         c &= 0xff; /* fight libc's sign extension */
  40.         for (on_off = complementary; on_off->opt_char != c; on_off++) {
  41.             if (on_off->opt_char == '\0' ) {
  42.                 goto error;
  43.             }
  44.         }
  45.         if (flags & on_off->incongruously)
  46.             goto error;
  47.         trigger = on_off->switch_on & on_off->switch_off;
  48.         flags &= ~(on_off->switch_off ^ trigger);
  49.         flags |= on_off->switch_on ^ trigger;
  50.         flags ^= trigger;
  51.         if (on_off->counter)
  52.             (*(on_off->counter))++;
  53.         if (optarg) {
  54.             if (on_off->param_type == PARAM_LIST) {
  55.                 llist_add_to_end((llist_t **)(on_off->optarg), optarg);
  56.             } else if (on_off->param_type == PARAM_INT) {
  57.                 *(unsigned*)(on_off->optarg) = xatoi_positive(optarg);
  58.             } else if (on_off->optarg) {                //都是string类型,就把optarg赋给on_off->optarg就是了
  59.                 *(char **)(on_off->optarg) = optarg;
  60.             }
  61.         }
  62.     }

  63.     /* check depending requires for given options */
  64.     for (on_off = complementary; on_off->opt_char; on_off++) {
  65.         if (on_off->requires
  66.          && (flags & on_off->switch_on)
  67.          && (flags & on_off->requires) == 0
  68.         ) {
  69.             goto error;
  70.         }
  71.     }
  72.     if (requires && (flags & requires) == 0)
  73.         goto error;
  74.     argc -= optind;
  75.     if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
  76.         goto error;

  77.     option_mask32 = flags;
  78.     return flags;

  79.  error:
  80.     if (first_char != '!')
  81.         bb_show_usage();
  82.     return (int32_t)-1;
  83. }
3.
  1. typedef struct {
  2.     unsigned char opt_char;
  3.     smallint param_type;
  4.     unsigned switch_on;
  5.     unsigned switch_off;
  6.     unsigned incongruously;
  7.     unsigned requires;
  8.     void **optarg;            
  9.     int *counter;
  10. } 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
  1. #include <unistd.h>
  2. #include <stdarg.h>
  3. int getopt32(int argc, char** argv, char* opts, ...)
  4. {
  5.     int i=0, ret;
  6.     va_list p;
  7.     char *s;
  8.     void **my_arg[1024];

  9.     va_start(p, opts);

  10.     s=opts; //s
  11.     while(*s++)
  12.     {
  13.         if(*s != ':')
  14.             continue;
  15.         //找到两个参数cc与buf的地址,保存到my_arg数组中 
  16.         my_arg[i++] = va_arg(p, void**);
  17.     }
  18.     
  19.     i=0;
  20.     while((ret=getopt(argc, argv, opts)) != -1)
  21.     {
  22.         if(optarg == NULL)
  23.             continue;
  24.         dbmsg("optarg=%s, strlen(optarg)=%d", optarg, strlen(optarg));
  25.         //*(char **)(my_arg)[i] = optarg;
  26.         memcpy((char **)(my_arg)[i], optarg, strlen(optarg));   //将从命令行传来的参数解析,并写到c与buf中
  27.         dbmsg("addr=0x%x", (char **)(my_arg)[i]);
  28.         dbmsg("%s", (char **)(my_arg)[i]);
  29.         i++;
  30.     }
  31. }

  32. int main ( int argc, char *argv[] )
  33. {
  34.     char c[1024];
  35.     char buf[1024];
  36.     dbmsg("addr c=0x%x,buf=0x%x", c, buf);   //c与buf的地址
  37.     getopt32(argc, argv, "hc:s:", c, buf);
  38.     dbmsg("c=%s,buf=%s", c, buf);            //c与buf的结果  
  39.     return EXIT_SUCCESS;
  40. }
现在这个原理就很明显了:
    a. 找到可变参数的地址
    b. 解析DUAqfbc:w:I:s:字符串,遇到:

2.2 运行结果:
  1. cong@msi:/work/test/busytest/1varg$ ./varg -s 1 -c 2
  2. varg.c:main[40]: addr c=0x5439390,s=0x5439790
  3. varg.c:getopt32[27]: optarg=1, strlen(optarg)=1
  4. varg.c:getopt32[30]: addr=0x5439390
  5. varg.c:getopt32[31]: 1
  6. varg.c:getopt32[27]: optarg=2, strlen(optarg)=1
  7. varg.c:getopt32[30]: addr=0x5439790
  8. varg.c:getopt32[31]: 2
  9. varg.c:main[42]: c=1,s=//

  10. cong@msi:/work/test/busytest/1varg$ ./varg -s 1
  11. varg.c:main[40]: addr c=0x39c4ec70,s=0x39c4f070
  12. varg.c:getopt32[27]: optarg=1, strlen(optarg)=1
  13. varg.c:getopt32[30]: addr=0x39c4ec70
  14. varg.c:getopt32[31]: 1
  15. varg.c:main[42]: c=1,s=       //不//这儿有个bug

  16. cong@msi:/work/test/busytest/1varg$ ./varg -c 2
  17. varg.c:main[40]: addr c=0x8fcdb0e0,s=0x8fcdb4e0
  18. varg.c:getopt32[27]: optarg=2, strlen(optarg)=1
  19. varg.c:getopt32[30]: addr=0x8fcdb0e0
  20. varg.c:getopt32[31]: 2
  21. 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改进后的代码
  1. #include "utils.h"
  2. #include <unistd.h>
  3. #include <stdarg.h>
  4. int getopt32(int argc, char** argv, char* opts, ...)
  5. {
  6.     int i=0, ret,len=0;    //len-->带:的参数的个数
  7.     va_list p;
  8.     char *s;
  9.     void **my_arg[1024];
  10.     char opt_char[1024];

  11.     va_start(p, opts);

  12.     s=opts; //s
  13.     while(*s++)
  14.     {
  15.         if(*s != ':')
  16.             continue;
  17.         //get args addr
  18.         my_arg[len] = va_arg(p, void**);      //获取c与s,即传给getopt32的可变参数的地址
  19.         opt_char[len] = *(s-1);               //保存"hc:s:"中的c与s
  20.         len++;
  21.     }
  22.     
  23.     while((ret=getopt(argc, argv, opts)) != -1)
  24.     {
  25.         if(optarg == NULL)
  26.             continue;
  27.         dbmsg("ret=%c,optarg=%s, strlen(optarg)=%d",ret, optarg, strlen(optarg));
  28.         for(i=0; i<len; i++)
  29.         {
  30.             if(opt_char[i] == ret)     //比较<"hc:s:"cs>与ret是否相同
  31.             {
  32.                 //*(char **)(my_arg)[i] = optarg;
  33.                 memcpy((char **)(my_arg)[i], optarg, strlen(optarg));
  34.                 dbmsg("addr=0x%x", (char **)(my_arg)[i]);
  35.                 dbmsg("%s", (char **)(my_arg)[i]);
  36.             }
  37.         }
  38.     }
  39. }

  40. int main ( int argc, char *argv[] )
  41. {
  42.     char c[1024];
  43.     char s[1024];
  44.     dbmsg("addr c=0x%x,s=0x%x", c, s);
  45.     getopt32(argc, argv, "hc:s:", c, s);
  46.     dbmsg("c=%s,s=%s", c, s);
  47.     return EXIT_SUCCESS;
  48. }
这个地方太不好说明了,都叫参数,没法区分,直接看代码吧!
3.2结果
  1. cong@msi:/work/test/busytest/2varg$ ./varg -s 1 -c 2
  2. varg.c:main[48]: addr c=0x59df07a0,s=0x59df0ba0
  3. varg.c:getopt32[29]: ret=s,optarg=1, strlen(optarg)=1
  4. varg.c:getopt32[37]: addr=0x59df0ba0
  5. varg.c:getopt32[38]: 1
  6. varg.c:getopt32[29]: ret=c,optarg=2, strlen(optarg)=1
  7. varg.c:getopt32[37]: addr=0x59df07a0
  8. varg.c:getopt32[38]: 2
  9. varg.c:main[50]: c=2,s=1      //

  10. cong@msi:/work/test/busytest/2varg$ ./varg -s 1
  11. varg.c:main[48]: addr c=0x34bba3a0,s=0x34bba7a0
  12. varg.c:getopt32[29]: ret=s,optarg=1, strlen(optarg)=1
  13. varg.c:getopt32[37]: addr=0x34bba7a0
  14. varg.c:getopt32[38]: 1
  15. varg.c:main[50]: c=,s=1        //

  16. cong@msi:/work/test/busytest/2varg$ ./varg -c 2
  17. varg.c:main[48]: addr c=0xa3100400,s=0xa3100800
  18. varg.c:getopt32[29]: ret=c,optarg=2, strlen(optarg)=1
  19. varg.c:getopt32[37]: addr=0xa3100400
  20. varg.c:getopt32[38]: 2
  21. varg.c:main[50]: c=2,s=        //
3.3 代码
2varg.rar (下载后改名为2varg.tar.gz)


阅读(3429) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

adaslove5202016-04-14 23:11:43

写的很好