getopt value stays null - c

I am passing my program inputs and I could see them in argv but getopt doesnt seem to have the argument that I expect.
This is how I run my prog: ./my_prog -X -f filename
<snip>
while ((opt = getopt(argc, argv, "Xf:eE:dD")) != EOF) {
switch (opt) {
case 'X':
case 'f':
if (optarg == NULL)
fput("no point of living", fp); << for debugging
</snip>
I always get optarg as null. WHY?

Your argument string does not have a : after the X (e.g. X:f) so optarg will always be null.
I'll also point out that generally in a switch statement you'll want a break after each case (generally, not always, but when parsing arguments usually), so:
switch ( ... ) {
case 'X': {
// do something
} break;
case 'f': {
// do something else
} break;
}

For who else get to this page:
From http://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html#Using-Getopt:
An option character in this string can be followed by a colon (‘:’) to indicate that it takes a required argument. If an option character is followed by two colons (‘::’), its argument is optional; this is a GNU extension.
so in your argument you might use:
"X:f:e:E:d:D:"
Had the same problem.

I just dealt with this issue, and it appears this question was never fully answered.
You have to make sure you're setting the external libc variable opterr = 0 before you call getopt; if you don't reset it and getopt previously had an error in another application anywhere in your system that used it, it will fail for the argument. I'll also reiterate the existing point that because you don't have a break statement after case 'X': that's a sure sign of an issue since it will fall through.
getopt only processes one argument at a time, so falling through case X into case f is a bad thing to do. You should always have a break in each case statement of a switch unless you are absolutely certain it should fall through (which is very rare in my experience). As another bit of general good practice, you should always enclose blocks of code in { } (referring to your conditional) unless it's a return statement or break or something that causes the program flow to to drop out of the current or parent block scope or to enter a new scope through a function or method call.
I think your option string Xf:eE:dD is fine. This indicates that:
1) The following will simply be option flags that always have a null argument: XedD
2) The following options will require an argument: fE
If this is the functionality you're looking for, the given option string is fine. If you're using GNU libc, per the other above answer, you can use :: after an option in the option string to indicate that the option might have an argument, but doesn't have to.
So at the top of your file make sure you at least have:
extern int opterr;
Then right before you call getopt for the first time in your code, set opterr to 0.
e.g.
opterr = 0;
while ((opt = getopt(argc, argv, "Xf:eE:dD")) != EOF) {
switch (opt) {
case 'X':
case 'f':
if (optarg == NULL)
fput("no point of living", fp); << for debugging
This should at least partially resolve your issue. Here's a link to an example:
http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html
Cheers,
Jon

I know this is old but I recently noticed changed behaviour in the way I used to use getopt years ago. Maybe it was a different environment but I find using it today requires the optarg to be DIRECTLY after the flag (no space) otherwise optarg is null.
Using your example, replace ./my_prog -X -f filename with ./my_prog -X -ffilename
I find that works fine even though it feels wrong. Hope this helps someone else out later. Make sure to try it both ways.

Related

How to parse unordered flags in arguments via getopt in C

int res = 0;
while ((res = getopt(argc, argv, "ivlcne")) != -1) {
switch (res)
{
case 'i':
pCurrentFlags->i = 1;
break;
case 'v':
pCurrentFlags->v = 1;
break;
default:
break;
}
}
Using such a code, I encounter a problem. If I write ./a.out -i filename -v in the terminal, the -v flag will not work.
UPDATE:
Commonly used practice to parse unordered flags is to parse all the arguments first and only after that handle them.
There is also a GNU implementation of the getopt() which supports that behavior as #Jonathan Leffler mentioned in the comments.
But from your copy, it is unclear what you are trying to do.
The v option in the code you provide needs an argument, but in the command line ./a.out -i filename -v it is not taking it.
If you need v as a non-parameter option, the easiest way to make it work is to change "ivlcne" with "i:v1:l:c:n:e" and with this way getopt() will no longer wait for an argument for v.

getopt giving -1 as return value

I am trying to see how getopts work. I wrote the code below but not sure what I am doing wrong. Please point me :
#include<unistd.h>
..
..
int main( int argc, char *argv[])
{
int ch=0;
while((ch=getopt(argc, argv, "ltR:")!=-1) // 0 here was by mistake. Changed to -1
{
printf("%d",ch); //This prints -1
switch(ch)
{
case 'l':
printf("l");
break;
case 't':
printf("t");
break;
case 'R':
printf("R");
break;
}
}
return 0;
}
$ ./a.out -ltR
$ -1
$ ./a.out -l
$ -1
May be I am doing a really mistake or missing out on some aspect of my understanding of getopt.
Made changes but still gives the same result:(
Thanks,
Faizan
I think your while expression should be
while((ch=getopt(argc, argv, "ltR")!=-1)
{..}
and the option should end with ':'
while((ch=getopt(argc, argv, "ltR:")!=-1)
{..}
or two ':' if switch is optional.
From the man page -1 indicates that all the arguments have been done, rather than 0 as you appear to be checking for.
man 3 getopt
If an option was successfully found, then getopt() returns the option character. If all command-line options have been parsed, then getopt() returns -1.
The code in your question doesn't parse out of the box so it doesn't appear to be a proper copy paste which makes spotting the error a lot harder. The brackets on the while loop might be the cause of your issue but it's hard to tell. If I copy paste your example and correct the bracket issue the code works as you expect it to.

C getopt multiple value

My argument is like this
./a.out -i file1 file2 file3
How can I utilize getopt() to get 3 (or more) input files?
I'm doing something like this:
while ((opt = getopt(argc, argv, "i:xyz.."))!= -1){
case 'i':
input = optarg;
break;
...
}
I get just the file1; how to get file2, file3?
I know this is quite old but I came across this in my search for a solution.
while((command = getopt(argc, argv, "a:")) != -1){
switch(command){
case 'a':
(...)
optind--;
for( ;optind < argc && *argv[optind] != '-'; optind++){
DoSomething( argv[optind] );
}
break;
}
I found that int optind (extern used by getopt() ) points to next position after the 'current argv' selected by getopt();
That's why I decrease it at the beginning.
First of all for loop checks if the value of current argument is within boundaries of argv (argc is the length of array so last position in array argv is argc-1).
Second part of && compares if the next argument's first char is '-'. If the first char is '-' then we run out of next values for current argument else argv[optind] is our next value. And so on until the argv is over or argument runs out of values.
At the end increment optind to check for the next argv.
Note that because we are checking 'optind < argc' first second part of condition will not be executed unless first part is true so no worries of reading outside of array boundaries.
PS I am a quite new C programmer if someone has an improvements or critique please share it.
If you must, you could start at argv[optind] and increment optind yourself. However, I would recommend against this since I consider that syntax to be poor form. (How would you know when you've reached the end of the list? What if someone has a file named with a - as the first character?)
I think that it would be better yet to change your syntax to either:
/a.out -i file1 -i file2 -i file3
Or to treat the list of files as positional parameters:
/a.out file1 file2 file3
Note that glibc's nonconformant argument permutation extension will break any attempt to use multiple arguments to -i in this manner. And on non-GNU systems, the "second argument to -i" will be interpreted as the first non-option argument, halting any further option parsing. With these issues in mind, I would drop getopt and write your own command line parser if you want to use this syntax, since it's not a syntax supported by getopt.
I looked and tried the code above, but I found my solution a little easier and worked better for me:
The handling I wanted was:
-m mux_i2c_group mux_i2c_out
(2 arguments required).
Here's how it panned out for me:
case 'm':
mux_i2c_group = strtol(optarg, &ch_p, 0);
if (optind < argc && *argv[optind] != '-'){
mux_i2c_out = strtol(argv[optind], NULL, 0);
optind++;
} else {
fprintf(stderr, "\n-m option require TWO arguments <mux_group> "
"<mux_out>\n\n");
usage();
}
use_mux_flag = 1;
break;
This grabbed the first value form me as normal and then just looked for the second, REQUIRED value.
The solution by GoTTimw has proven very useful to me. However, I would like to mention one more idea, that has not been suggested here yet.
Pass arguments as one string in this way.
./a.out -i "file1 file2 file3"
Then you get one string as a single argument and you only need to split it by space.

Where does getopt_long store an unrecognized option?

When getopt or getopt_long encounters an illegal option, it stores the offending option character in optopt. When the illegal option is a long option, where can I find out what the option was? And does anything meaningful get stored in optopt then?
I've set opterr = 0 to suppress the automatically printed error message. I want to create my own message that I can print or log where I'd like, but I want to include the name of the unrecognized option.
The closest I can find is that if you get a BADCH return the argv item that caused it is in argv[optind-1]. Seems like there should be a better way to find the problem argument.
You're quite right that the man page glosses right over these details, but enough hints can be gleaned from the source code, e.g., glibc's implementation in glibc-x.y.z/posix/getopt.c's _getopt_internal_r. (Perhaps that's the only interesting implementation of this GNU extension function?)
That code sets optopt to 0 when it encounters an erroneous long option, which I guess is useful to distinguish this case from an erroneous short option, when optopt will surely be non-NUL.
The error messages produced when opterr != 0 mostly print out the erroneous long option as argv[optind], and later code (always or -- conservatively -- at least mostly) later increments optind before returning.
Hence consider this program:
#include <getopt.h>
#include <stdio.h>
int main(int argc, char **argv) {
struct option longopts[] = {
{ "foo", no_argument, NULL, 'F' },
{ NULL, 0, NULL, 0 }
};
int c;
do {
int curind = optind;
c = getopt_long(argc, argv, "f", longopts, NULL);
switch (c) {
case 'f': printf("-f\n"); break;
case 'F': printf("--foo\n"); break;
case '?':
if (optopt) printf("bad short opt '%c'\n", optopt);
else printf("bad long opt \"%s\"\n", argv[curind]);
break;
case -1:
break;
default:
printf("returned %d\n", c);
break;
}
} while (c != -1);
return 0;
}
$ ./longopt -f -x --bar --foo
-f
./longopt: invalid option -- 'x'
bad short opt 'x'
./longopt: unrecognized option '--bar'
bad long opt "--bar"
--foo
Thus in these cases, by caching the pre-getopt_long value of optind, we're easily able to print out the same bad options as the opterr messages.
This may not be quite right in all cases, as the glibc implementation's use of its own __nextchar rather than argv[optind] (in the "unrecognized option" case) deserves study, but it should be enough to get you started.
If you think carefully about the relationship between optind and the repeated invocations of getopt_long, I think printing out argv[cached_optind] is going to be pretty safe. optopt exists because for short options you need to know just which character within the word is the problem, but for long options the problem is the whole current word (modulo stripping off option arguments of the form =param). And the current word is the one that getopt_long is looking at with the (incoming) optind value.
In the absence of a guarantee written in the documentation, I would be somewhat less sanguine about taking advantage of the optopt = 0 behaviour though.

command line processing library - getopt

Can someone help me with the getopt function?
When I do the following in main:
char *argv1[] = {"testexec","-?"};
char *argv2[] = {"testexec","-m","arg1"};
int cOption;
/* test for -? */
setvbuf(stdout,(char*)NULL,_IONBF,0);
printf("\n argv1 ");
while (( cOption = getopt (2, argv1, "m:t:n:fs?")) != -1) {
switch(cOption){
case 'm':
printf("\n -m Arg : %s \n",optarg);
break;
case '?':
printf("\n -? Arg ");
break;
case 'n':
printf("\n -n Arg : %s \n",optarg);
break;
}
}
printf("\n argv2 ");
while (( cOption = getopt (3, argv2, "m:t:n:fs?")) != -1) {
switch(cOption){
case 'm':
printf("\n -m Arg : %s \n",optarg);
break;
case '?':
printf("\n -? Arg : %s \n",optarg);
break;
case 'n':
printf("\n -n Arg : %s \n",optarg);
break;
}
}
I'm running this code on rhel3 which uses old libc version. I don't know which one to be exact.
Now the problem is getopt doesn't work the second time with argv2.
But if I comment out the first getopt call with argv1 , it works.
Can someone tell me what am I doing wrong here?
argv1 and 2 must end in 0:
char* argv1[] = {"par1", "par2", 0};
Edit: OK, I read the getopt man page and I found this:
The variable optind is the index of the next element to be processed in argv. The system initializes this value
to 1. The caller can reset it to 1 to restart scanning of the same argv, or when scanning a new argument vector.
So, making optind=1 between the two calls at getopt makes it work as expected.
The getopt() function uses some global variables, like optind and optarg, to store state information between calls. After you finish processing one set of options, there is data left in those variables that is causing problems with the next set of options. You could potentially try to reset getopt's state between calls by clearing the variables, but I'm not sure that would work since the function might use other variables which aren't documented and you'd never know if you'd gotten them all; besides, it would be absolutely nonportable (i.e. if the implementation of getopt() changes, your code breaks). See the man page for details. Best not to use getopt() for more than one set of arguments in a given program if you can help it.
I'm not sure if there is an actual function to reset getopt's state (or perhaps a reentrant version of the function, which lets you store the state in your own variables)... I seem to remember seeing something like that once, but I can't find it now that I look :-/
As stated in the man page:
"A program that scans multiple argument vectors, or rescans the same vector more than once, and wants to make use of GNU extensions such as '+' and '-' at the start of optstring, or changes the value of POSIXLY_CORRECT between scans, must reinitialize getopt() by resetting optind to 0, rather than the traditional value of 1. (Resetting to 0 forces the invocation of an internal initialization routine that rechecks POSIXLY_CORRECT and checks for GNU extensions in optstring.)"
Is there any reason why you are not using getopt_long() instead? On most platforms, getopt() just calls _getopt_long() with a switch to disable long arguments. That's the case with almost every platform that I know of (still in use), including Linux, BSD and even emerging OS's like HelenOS -, I know, I was the one who ported getopt to its libc :)
It is much easier on ANYONE using your program to have long options at least until they get used to using it.
getopt_long() will allow you to use two (or more) option indexes that can stay 'live' after they are done processing arguments, only the internal (global, non-reentrant) one would have to be re-set which is no big deal.
This lets you easily compare the argument count to the number of options actually passed in both invocations with many other benefits .. please consider not using the antiquated interface.
Look at getopt.h, you'll see what I mean.

Resources