getopt_long和get_opt是否会前进argv指针?

huangapple go评论58阅读模式
英文:

Does getopt_long and get_opt advance the argv pointer?

问题

I am tasked with rewriting the get_some_switches() function in Larry Wall's patch 1.3 (https://groups.google.com/g/mod.sources/c/xSQM63e39YY) using getopt_long().

get_some_switches()
{
register char *s;

rejname[0] = '\0';
if (!Argc)
    return;
for (Argc--,Argv++; Argc; Argc--,Argv++) {
    s = Argv[0];
    if (strEQ(s,"+")) {
        return; /* + will be skipped by for loop */
    }
    if (*s != '-' || !s[1]) {
        if (filec == MAXFILEC)
            fatal("Too many file arguments.\n");
        filearg[filec++] = savestr(s);
    }
    else {
        switch (*++s) {
        case 'b':
            origext = savestr(Argv[1]);
            Argc--,Argv++;
            break;
        case 'c':
            diff_type = CONTEXT_DIFF;
            break;
        case 'd':
            if (chdir(Argv[1]) < 0)
                fatal("Can't cd to %s.\n",Argv[1]);
            Argc--,Argv++;
            break;
        case 'D':
            do_defines++;
            Sprintf(if_defined, "#ifdef %s\n", Argv[1]);
            Sprintf(not_defined, "#ifndef %s\n", Argv[1]);
            Sprintf(end_defined, "#endif %s\n", Argv[1]);
            Argc--,Argv++;
            break;
        case 'e':
            diff_type = ED_DIFF;
            break;
        case 'l':
            canonicalize = TRUE;
            break;
        case 'n':
            diff_type = NORMAL_DIFF;
            break;
        case 'o':
            outname = savestr(Argv[1]);
            Argc--,Argv++;
            break;
        case 'p':
            usepath = TRUE; /* do not strip path names */
            break;
        case 'r':
            Strcpy(rejname,Argv[1]);
            Argc--,Argv++;
            break;
        case 'R':
            reverse = TRUE;
            break;
        case 's':
            verbose = FALSE;
            break;
#ifdef DEBUGGING
        case 'x':
            debug = atoi(s+1);
            break;
#endif
        default:
            fatal("Unrecognized switch: %s\n",Argv[0]);
        }
        }
    }
}

If I am reading the code correctly, this loop doesn't stop unless it hits a '+' or until it runs out of arguments and is incrementing argc down and argv up as it looks for flags and arguments. This way, when this function gets called again in reinitialize_almost_everything(), argc and argv are already pointing further in than it would have if it were called the first time.

In replacing it with getopt_long, will I have to find a way to increment argc and argv so that it will be ready for the next call, or will getopt_long remember where it left off?

Also, what does the condition !s[1] mean?

英文:

I am tasked with rewriting the get_some_switches() function in Larry Wall's patch 1.3 (<https://groups.google.com/g/mod.sources/c/xSQM63e39YY>) using getopt_long().

get_some_switches()
{
register char *s;
rejname[0] = &#39;\0&#39;;
if (!Argc)
return;
for (Argc--,Argv++; Argc; Argc--,Argv++) {
s = Argv[0];
if (strEQ(s,&quot;+&quot;)) {
return; /* + will be skipped by for loop */
}
if (*s != &#39;-&#39; || !s[1]) {
if (filec == MAXFILEC)
fatal(&quot;Too many file arguments.\n&quot;);
filearg[filec++] = savestr(s);
}
else {
switch (*++s) {
case &#39;b&#39;:
origext = savestr(Argv[1]);
Argc--,Argv++;
break;
case &#39;c&#39;:
diff_type = CONTEXT_DIFF;
break;
case &#39;d&#39;:
if (chdir(Argv[1]) &lt; 0)
fatal(&quot;Can&#39;t cd to %s.\n&quot;,Argv[1]);
Argc--,Argv++;
break;
case &#39;D&#39;:
do_defines++;
Sprintf(if_defined, &quot;#ifdef %s\n&quot;, Argv[1]);
Sprintf(not_defined, &quot;#ifndef %s\n&quot;, Argv[1]);
Sprintf(end_defined, &quot;#endif %s\n&quot;, Argv[1]);
Argc--,Argv++;
break;
case &#39;e&#39;:
diff_type = ED_DIFF;
break;
case &#39;l&#39;:
canonicalize = TRUE;
break;
case &#39;n&#39;:
diff_type = NORMAL_DIFF;
break;
case &#39;o&#39;:
outname = savestr(Argv[1]);
Argc--,Argv++;
break;
case &#39;p&#39;:
usepath = TRUE; /* do not strip path names */
break;
case &#39;r&#39;:
Strcpy(rejname,Argv[1]);
Argc--,Argv++;
break;
case &#39;R&#39;:
reverse = TRUE;
break;
case &#39;s&#39;:
verbose = FALSE;
break;
#ifdef DEBUGGING
case &#39;x&#39;:
debug = atoi(s+1);
break;
#endif
default:
fatal(&quot;Unrecognized switch: %s\n&quot;,Argv[0]);
}
}
}
}

If I am reading the code correctly, this loop doesn't stop unless it hit a '+' or until it runs out of arguments and is incrementing argc down and argv up as it looks for flags and arguments. This way, when this function gets called again in reinitialize_almost_everything(), argc and argv is already pointing further in than it would have if it were called the first time.

In replacing it with getopt_long, will I have to find a way to increment argc and argv so that it will be ready for the next call, or will getopt_long remember where it left off?

Also, what does the condition !s[1] mean?

答案1

得分: 2

getopt_longget_opt像所有的C函数一样,接收参数时是按值传递的。因此,它们无法修改调用者的相应参数。

然而,如果参数是指针,比如argv,函数可以修改指向的数据。GNU的getopt()getopt_long()的实现利用这一能力,在多次调用中,将非选项参数移到列表的末尾。但这不会妨碍再次解析选项。

如果我正确阅读代码,这个循环只有在遇到'+'或用完参数后才会停止,它会递减argc并递增argv,同时查找标志和参数。这样,当这个函数在reinitialize_almost_everything()中再次被调用时,argcargv指向的位置比第一次调用时要进一步。

这个函数使用外部的ArgcArgv变量,这些变量与C main()函数的参数具有相同的类型和形式,函数会修改它们。但不清楚这些变量何时以及如何获得它们的初始值,以及这些值与main()函数的参数的值有何关联,后者是main()本地的。还不清楚其他函数(如reinitialize_almost_everything())可能对这些值做些什么。

使用getopt()getopt_long()会跟踪它们在参数列表中的进度。在通过参数列表时,调用者需要每次传递相同的参数值。

此外,条件!s[1]中的感叹号(!)是逻辑非运算符。因此,当s[1]的值为0时,!s[1]的值为1;否则,它的值为0。在代码中的特定上下文中,这个表达式用于测试s中索引1处的char是否是字符串终止符。

英文:

> Does getopt_long and get_opt advance the argv pointer?

Like all C functions, getopt() and getopt_long() receive their parameters by value. They cannot, therefore, alter the caller's corresponding arguments.

Where an argument is a pointer, however, such as argv, a function can modify the data to which it points. GNU's implementation of getopt() and getopt_long() makes use of this capability, over several calls, to permute the non-option arguments to the end of the list. This poses no impediment to parsing the options again, however.

> If I am reading the code correctly, this loop doesn't stop unless it hit a '+' or until it runs out of arguments and is incrementing argc down and argv up as it looks for flags and arguments. This way, when this function gets called again in reinitialize_almost_everything(), argc and argv is already pointing further in than it would have if it were called the first time.

The function presented works with variables Argc and Argv that are external to the function. The code suggests that these have the same types as and form similar to the parameters to a C main() function, and the function does modify these. But it is not clear where or when these variables get their initial values, or exactly how those values are related to those of the main() function's parameters, which are local to main(). Or what other functions, such as reinitialize_almost_everything(), may do to those values.

> In replacing it with getopt_long, will I have to find a way to increment argc and argv so that it will be ready for the next call, or will getopt_long remember where it left off?

getopt() and getopt_long() track their progress through the argument list. During a given pass through an argument list, callers are expected to pass the same parameter values each time.

> Also, what does the condition !s[1] mean?

The exclamation point (!) is the logical negation operator. Thus, !s[1] evaluates to 1 when s[1] evaluates to 0; otherwise it evaluates to 0. In the particular context where that expression appears in the code presented, it is testing whether the char at index 1 in s is a string terminator.

huangapple
  • 本文由 发表于 2023年2月27日 11:22:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75576519.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定