C getopt multiple value - c

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.

Related

Seperating options from non-option arguments in a command-line program

I am trying to write a limited version of ls w/ some options.
However, I am stuck on the problem of parsing out my options from my arguments in a clean manner.
For example:
$ ls -l -t somefile anotherFile
$ ls somefile -lt anotherFile
have the same behavior.
This poses two problems for me:
It makes using argc a bit more difficult. For example I would consider the arguments ls -lt and ls to both have 0 arguments (other than the name of the command) however argc counts -l as an argument.
Therefore the naive implementation of :
if( argc == 1) {list all the contents of cwd}
does not work.
Is there a built-in way to get the options as well as the option count, or do I have to roll my own function?
I have to consider all the different ways options can be arranged and be careful not to get an option mixed up as a file name or directory name. It seems like the cleanest solution is to separate the options from the file arguments from the start. Is there an idiomatic way to do this / is there standard library calls that do this?
There is no built-in argument parsing help, but getopt is the "standard" method for argument parsing.
For simple apps, I sometimes roll my own with something like:
int pos=0;
argc--;argv++;
while (argc > 0) {
if (*argv[0]=='-') {
switch ((*argv)[1]) {
case 'l': //-l argument
save_option_l(++argv);
argc--; //we consumed one name
break;
//... other -options here ...
default:
usage("unrecognized option %s", *argv);
}
}
else {
save_positional_argument(argv,pos++);
}
argv++;
argc--;
}
In this case, I require the modifiers to directly follow the flags. Don't support variable usage like your first example, unless there are very strong reasons to do so.
If you have Gnu's implementation of getopt, it will do all that for you.
Posix standard getopt terminates option processing when it hits the first non-option argument. That conforms to Posix guidelines for utility argument parsing, and many of us prefer this behaviour. But others like the ability to intermingle options and non-options, and that's the norm for Gnu utilities unless you set an environment variable with the ungainly name POSIXLY_CORRECT.
Consistent with that preference, Gnu getopt parses arguments:
The default is to permute the contents of argv while scanning it so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this.
Note the wording about permuting arguments. This means that if you start with
ls somefile -lt anotherFile
Gnu getopt will:
Report a l
Report a t
Report end of options (-1), leaving optind with the value 2 and argv now looking like:
ls -lt somefile anotherFile
So now you can process your non-option arguments with:
for (int argno = optind; argno < argc; ++argno) {
/* Do something with argv[argno] */
}
Also, you can tell how many non-option arguments you received with argc-optind, and if argc == optind, you know there weren't any.
Unbundling -lt into two options is standard Posix getopt behaviour. You can combine options lime that as long as the first one doesn't take an argument.

How does "optind" get assigned in C?

I am creating this question because there is not much about how this optind gets assigned for each loop.
Man page says :
The variable optind is the index of the next element to be processed in argv. The system initializes this value to 1.
Below, I have a simple code I got from Head First C and in the code we subtract "optind" from "argc" and we get the number of leftover arguments, which will we use then to print leftover arguments as "Ingredients".
#include <unistd.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
char* delivery = "";
int thick = 0 ;
int count = 0;
char ch;,
for(int i = 0; i < argc;i++){
//This is , to show the whole array and their indexes.
printf("Argv[%i] = %s\n", i, argv[i]);
}
while((ch = getopt(argc, argv, "d:t")) != -1 ){
switch(ch) {
case 'd':
printf("Optind in case 'd' : %i\n",optind);
delivery = optarg;
break;
case 't':
printf("Optind in case 't' : %i\n",optind);
thick = 1;
break;
default:
fprintf(stderr,"Unknown option: '%s'\n", optarg); // optional argument.
return 1;
}
}
argc -= optind;
argv += optind;
printf("Optind : %i and Argc after the subctraction : %i\n",optind,argc);
if(thick)
puts("Thick crust");
if(delivery[0]){
printf("To be delivered %s\n", delivery);
}
puts("Ingredients:");
for(count = 0; count < argc ; count ++){
puts(argv[count]);
}
return 0;
}
So at the beginning of the code the for loop writes all the array and its indexes to see the difference.
Then I run the code with :
./pizzaCode -d now Anchovies Pineapple -t //-t is intentionally at the end
I was told that if the flag was at the end it wouldn't get in the 't' case but somehow it works on my ubuntu. That is another thing I wonder but not the main question.
So the output is as follows :
Argv[0] = ./pizzaCode
Argv[1] = -d
Argv[2] = now
Argv[3] = Anchovies
Argv[4] = Pineapple
Argv[5] = -t
Optind in case 'd' : 3
Optind in case 't' : 6
Optind : 4 and Argc after the subctraction : 2
Thick crust
To be delivered now
Ingredients:
Anchovies
Pineapple
1- Everything is fine so far, the problem is how come argv[0] and argv1 became Anchovies and Pineapple ?
2- And another question is how did optind become 3 in case 'd'? Since 'd's index is 1 and the next index is 2.
3- How did optind become 4 after the loop ? It was 6 in the case 't'.
I hope my question is clear for you all, I am just trying to understand the logic instead of having to memorize it.
Thank you in advance!
The manpage for Gnu getopt documents this non-standard implementation:
By default, getopt() permutes the contents of argv as it scans, so that eventually all the nonoptions are at the end.
This is actually not quite true; the permutation occurs after the last option is scanned, as you have seen in your example. But the effect is the same; argv is permuted so that nonoptions are at the end, and optind is modified to index the first nonoption.
If you want to avoid the permutation, so that getopt behaves as per Posix:
If the first character of optstring is '+' or the environment variable POSIXLY_CORRECT is set, then option processing stops as soon as a nonoption argument is encountered.
In this case, no permuting is done and optind's value is preserved.
Setting POSIXLY_CORRECT has other consequences, documented here and there in the manpages for various Gnu utilities. My habit is to use + as the first character of the option string (unless I actually want non-Posix behaviour), but arguably setting the environment variable is more portable.
For your specific questions:
Why are the non-option arguments at argv[0] and argv[1]?
Because you modified argv: argv += optind;
Why is optind 3 in the loop processing option -d?
Because that option takes an argument. So the next argument is the one following the now argument, which has already been processed (by placing a pointer to it into optarg).
How did optind become 4?
As above, it was modified after the argv vector was permuted, in order for optind to be the index of the first "unprocessed" non-option argument.

How to use command line options in a c command line tool?

I am trying to understand how to use command line options with a command line c tool and I came accross this example.Can some one explain how the code flow works,I am not able to understand it,also I understand that it uses a getopt() function which is inbuilt.
The exe called is rocket_to and it has two command line options, e and a. e option takes 4 as an argument and a option takes Brasalia,Tokyo,London as argument.
Can some one explain how the code works?
This is the actual code:
command line:
rocket_to -e 4 -a Brasalia Tokyo London
code:
#include<unistd.h>
..
while((ch=getopt(argc,argv,"ae:"))!=EOF)
switch(ch){
..
case 'e':
engine_count=optarg;
..
}
argc -=optind;
argv +=optind;
There are many manual pages for getopt() including the POSIX specification. They describe what the getopt() function does. You can also read the POSIX Utility Conventions which describes how arguments are handled by most programs (but there are plenty of exceptions to the rules, usually because of historical, pre-POSIX precedent).
In the example outline code, the -e option takes an argument, and that is the 4 in the example command line. You can tell because of the e: in the third argument to getopt() (the colon following the letter indicates that the option takes an argument). The -a option takes no argument; you can tell because it is not followed by a colon in the third argument to getopt(). The names Brasilia, Tokyo, London are non-option arguments after the option processing is complete. They're the values in argv[0] .. argv[argc-1] after the two compound assignments outside the loop.
The use of EOF is incorrect; getopt() returns -1 when there are no more options for it to process. You don't have to include <stdio.h> to be able to use getopt().
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int ch;
int aflag = 0;
char *engine_count = "0";
while ((ch = getopt(argc, argv, "ae:")) != -1)
{
switch (ch)
{
case 'a':
aflag = 1;
break;
case 'e':
engine_count = optarg;
break;
default:
fprintf(stderr, "Usage: %s [-a][-e engine] [name ...]\n", argv[0]);
exit(EXIT_FAILURE);
}
}
argc -= optind;
argv += optind;
printf("A flag = %d\n", aflag);
printf("Engine = %s\n", engine_count);
for (int i = 0; i < argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
return 0;
}
That is working code which, if compiled to create a program rocket_to, produces:
$ ./rocket_to -e 4 -a Brasilia Tokyo London
A flag = 1
Engine = 4
argv[0] = Brasilia
argv[1] = Tokyo
argv[2] = London
$ ./rocket_to -a -e 4 Brasilia Tokyo London
A flag = 1
Engine = 4
argv[0] = Brasilia
argv[1] = Tokyo
argv[2] = London
$ ./rocket_to -e -a 4 Brasilia Tokyo London
A flag = 0
Engine = -a
argv[0] = 4
argv[1] = Brasilia
argv[2] = Tokyo
argv[3] = London
$
From the getopt man page:
The getopt() function parses the command-line arguments. Its arguments argc and argv are the argument count and array as passed to
the main() function on program invocation. An element of argv that starts with '-' (and is not exactly "-" or "--") is an option element. The characters of this element (aside from the initial '-') are option characters. If getopt() is called repeatedly, it
returns successively each of the option characters from each of the option elements.
The 3rd argument to getopt() are the valid options. If the option is followed by a colon it requires an argument. The argument can be accessed through the optarg variable. So in your example you have two options: 'a' which takes no argument and 'e' which takes an argument.
If getopt() finds an options it returns the character. If all options are parsed it returns -1 and if an unknown option is found it returns -1.
So your code loops through all options and processes them in a switch statement.
Next time when you have trouble understanding something like this try to run man <unknown function> first.

getopt value stays null

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.

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