51、【OS】【Nuttx】【OSTest】参数解析:参数处理过程
背景
接上两篇 blog:
49、【OS】【Nuttx】【OSTest】参数解析:测试项
50、【OS】【Nuttx】【OSTest】参数解析:函数定义
getopt_common
来看 getopt_common 的实现过程
- 首先校验输入参数是否为空,如果没有输入参数,则没必要进行解析,这里应该用卫语句来进行校验,可以减少圈复杂度;另外,这里判断 go_optind 是否小于 1 有点多余,因为首先没看到程序中有对 go_optind 进行清零操作的地方,其次 go_binitialized 在参数解析结束时会自动设置为 false,用 go_binitialized 对是否需要初始化判断已经足矣。
- 初始化完之后,接下来判断是否正在进行一个新的选项解析,上篇 blog 提到 go_optptr 为内部指针,指向当前正在解析的选项字符串的字符位置,如果 go_optptr 为空,说明此时为首次进行参数解析,如果 *go_optptr 为 \0,说明当前的选项已经解析完,可以开始下一个选项的解析
- 如果 go_optptr 不为空,说明不是首次解析,此时由于 *go_optptr 为 \0,说明当前选项已经解析完,开始执行下一选项解析(go_optind++)
- 如果索引超出选项个数 argc,则参数解析结束;或者发现选项中第一个字符不是 ‘-’,参数解析也结束,因为语法不对
- 如果选项没解析完,且语法也正确,则跳过第一个字符 ‘-’,进行后续字符的解析
特殊处理只有一个 ‘-’ 或者 ‘-:’ 的情况,这两种都属于异常情况,解析模块需要跳过异常选项,进行下一轮解析
检查是否为长选项解析模式,这里 long_mode 和 long_only_mode 都会进入该分支,如果下一个字符也是 ‘-’,说明为 long_mode,跳过字符 ‘-’,进行长选项解析 getopt_long_option
从 getopt_mode_e 类型定义可以看到,long_mode 和 long_only_mode 都有 GETOPT_LONG_BIT
如果不是 long_mode,接下来判断是不是 long_only_mode,如果为 long_only_mode,进行长选项解析 getopt_long_option,如果遇到未识别的长选项(可能是选项不匹配,或者选项的参数不匹配),将跳过该选项,进行下一轮选项解析
进行完长选项解析后,再进行短选项解析,这里如果 optstring(合法短选项)为空,在长选项模式中,将跳过该选项,进行下一轮选项解析;如果是短选项模式,将直接结束参数解析(因为没有合法的短选项进行参考)
- 首先看 optstring (合法短选项)第一个字符是不是冒号,如果是冒号,说明前面还少了一个选项参数,并跳过这个冒号
- optstring 的类型为 const char *,解引用后得到的是一个字符,而非字符串
- strchr 判断该选项是否为合法字符串,如果 optchar 为空,说明该选项为非法选项,将跳过该选项进行下一轮选项解析
- optchar[0] 为合法短选项,接下来看 optchar[1] 是不是冒号,如果非冒号,说明该选项不带参数
- 如果为冒号,首先正常情况下,选项和选项所带的参数是分开的,比如选项 -a 是 argv[0],但选项 -a 带的参数在 argv[1],那么解析完该选项及其参数,需要两轮解析,也就是调用 getopt_common 两次
- 这里考虑了一种特殊的情况,选项和参数混在一起,此时,从理论上,解析完这个选项参数,只需要一轮,也就是这里的条件分支,但实际上很少有人这么用,所以这里先不考虑这种场景
如果下一个待解析项不是 ‘-’ 开头,那么默认它为该选项的参数,此时返回该参数出去,optind 索引增加 2(选项 + 参数),否则就是不带参数,此时根据该选项参数是不是必须的,决定是返回该选项,还是 ‘?’