getopt_long() function does not return ':' for missing in command line arguments

I am wondering why getopt_long() in the following code does not return ':' for missing values for the current defined options in my program. Also, when I would like to print optopt and opterr, it does not reflect the current status of my program. Thank you very much!

#include <iostream>
#include <vector>
#include <getopt.h>//getopt_long
#include <sys/stat.h>//stat
#include <unistd.h>
#include <cstdlib>
struct program_options
{
int k;
int s;
std::vector<std::string> read_files;
bool verbose;
program_options():k(31),s(13),verbose(false){}
};

void parse_options(int argc,char **argv,program_options &opt)
{
int verbose_flag=0;
const char* opt_string =":k:s:";
static struct option long_options[]=
{
{"verbose",no_argument,&verbose_flag,1},
{"ksize",required_argument,0,'k'},
{"gsize",required_argument,0,'s'}
};
int option_index=0;
int ch;
while(true)
{
ch=getopt_long(argc,argv,opt_string,long_options,&option_index);
if(ch==-1)
break;
if(ch=='k')
{opt.k=atoi(optarg);}
else if(ch=='s')
{opt.s=atoi(optarg);}
else if(ch=='?')
{std::cout<<" invalid option "<<std::endl;exit(1);}
else if(ch==':')
{std::cout<<" option with missing argument"<<std::endl;exit(1);} //not detect



}

for(int i=optind;i<argc;++i)
{opt.read_files.push_back(argv[i]);}
if(verbose_flag)
{opt.verbose=true;}
}
bool check_options(program_options &opt)
{
bool success=true;
std::cerr<<std::endl;
if(opt.read_files.size()==0)
{std::cerr<<"--- no read files specified as inputs"<<std::endl;success=false;}
else
{
struct stat stat_file_info;
int int_stat;
std::vector<std::string>::const_iterator it;
for(it=opt.read_files.begin();it != opt.read_files.end();++it)
{
int_stat=stat(it->c_str(),&stat_file_info);
if(int_stat != 0)
{
std::cerr<<"--- error: file not found "<<*it<<std::endl;
success=false;

}//if
}//for


}//else

}

int main(int argc,char** argv)
{
program_options opt;
parse_options(argc,argv,opt);
if(!check_options(opt))
{

exit(1);
}

return 0;

}

when I use the command line like this:
./a.out -k 5 -s 6 /home/Documents/Data.txt it works fine
but when I use (missing argument value) :
./a.out -k 5 -s /home/Documents/Data.txt it sys:
no read files specified as inputs and it should be: " option with missing argument"
Last edited on
Provide runnable code and an example run
I edited the post to provide runnable code!
/home/Documents/Data.txt is considered the argument for the -s option (it follows it)

By the way, you are missing return statement in your `check_options()' function
Last edited on
The parsing of command line argument should be like: k has integer value and s has integer value and any thing else it should be the name of the file. As you said /home/Documents/Data.txt is taken as the argument for -s which it should not because -s should be detected as missing argument value case ':' .
Last edited on
":k:s:"
you say that the -s option has one argument, you don't specify that it is a number (afaik, you can't do it)
getopt_long() gives you whatever follows -s as argument, in this case /home/Documents/Data.txt, it is your job to validate it (perhaps use strtol() instead of atoi())


PS: ¿what does the first colon mean?
Last edited on
If getopt_long() encounters an option character that was not in optstring ":k:s:", then '?' is returned. If getopt() encounters an option with a missing argument, then the return value depends on the first character in optstring ":k:s:" if it is ':', then ':' is returned;

This why I put : and it does not work in my code :-(
It does work, there is no argument missing.

1
2
3
./a.out -k -s 3 //the argument of `k' is missing
./a.out -k 5 -s //the argument of `s' is missing
./a.out -k 5 -s hello.txt //no arguments missing 
The argument is not missing, it's invalid


1
2
3
4
5
6
7
8
9
10
11
		else if (ch == 's')
		{
			std::istringstream argument(optarg);
			if(
				not(argument>>opt.s>>std::ws) //reading failed
				or not argument.eof() //there are more characters (by instance, 10asdf)
			){
				std::cerr << "Invalid argument for option 's'. Expected a number, got " << optarg << '\n';
				exit(1);
			}
		}
$ ./a.out -k 5 -s data.txt
Invalid argument for option 's'. Expected a number, got data.txt
Last edited on
Topic archived. No new replies allowed.