getopt_long acting weirdly - c++

I'm writing some code for parsing the command line input. The way I use getopt_long is as follows:
int c = 0;
static struct option long_options[] =
{
{"mode", 1, NULL, 'm'},
{"help", 0, NULL, 'h'},
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, "mh", long_options, NULL))!=-1)
{
switch(c)
{
case 0:
{
cerr<<"Usage: ./program <-m> <-h>"<<endl;
exit(1);
break;
}
case 'm':
{
if (!strcmp(optarg, "small"))
mode = 0;
else if (!strcmp(optarg, "medium"))
mode = 1;
else if (!strcmp(optarg, "large"))
mode = 2;
else{
cerr<<"Invalid mode "<<optarg<<endl;
exit(1);
}
break;
}
case 'h':
{
cerr<<"See man page for help."<<endl;
exit(0);
}
default:
{
cerr<<"Unrecognized argument!"<<endl;
exit(1);
}
}
}
I tested the following:
1)
./program
The program doesn't enter the while-loop. Variable c is inspected to be -1.
2)
./program -h
Works well.
3)
./program -m small
The program exit with Segmentation Fault throwing from strcmp().
Thanks for any help.

Here is an example how to parse options with getopt_long() and correctly handle its return values, such as end of options, missing arguments and unknown options:
struct Options
{
std::string username = "guest";
void parse_command_line(int ac, char** av) try {
enum {
HELP
, USER
};
// This array must be in the same order as the enum.
option const options[] = {
{"help", no_argument, nullptr, HELP}
, {"username", required_argument, nullptr, USER}
, {}
};
::opterr = 0;
for(int c; -1 != (c = getopt_long(ac, av, ":h", options, nullptr));) {
switch(c) {
// both short and long option
case 'h':
case HELP:
usage(av, EXIT_SUCCESS);
break;
// only long option
case USER:
username = ::optarg; //
break;
case ':': // missing argument
throw Exception("--%s: an argument required", options[::optopt].name);
case '?': // unknown option
throw Exception("%s: unknown option", av[optind - 1]);
}
}
}
catch(std::exception& e) {
fprintf(stderr, "error: %s\n", e.what());
usage(av, EXIT_FAILURE);
}
};
Note, that it is not necessary to have a corresponding short option for each long option.

Related

How send a structure through fifo

HI!
I am trying to pass whole structure from one program and read it in another using fifo.
I'm using read and write functions. I had a problem with putting my structure into this functions. When I did it and tried to send and receive I get an error (core dump) or I recived some trash. I dont know exactly, where my problem take place (in receiver or sender). How can I send/receive my structure, or what i have wrong in my code.Here is my code...Receiver
struct data
{
char* message;
int size;
vector <times> prog;
};
int if_fifo(char* name)
{
struct stat info;
int score = stat(name,&info);
if(S_ISFIFO(info.st_mode))
{
return 1;
}
else
{
return 0;
}
}
int fifo_in(char* name)
{
data msg;
int pip;
pip = open(name, O_RDONLY | O_NONBLOCK);
while(1)
{
int hr = read(pip,&msg,sizeof(msg));
if(hr != 0)
{
cout << "Message: " << msg.message << endl;
}
}
cout << "O.K." << endl;
return 0;
}
int main(int argc, char** argv) {
int c, status_in, status_out;
char* input;
char* output;
float del;
if(argc < 5)
{
cout << "Za malo podanych parametrow" << endl;
return 1;
}
else
{
while ((c = getopt(argc, argv, "iod:")) != -1)
{
switch (c)
{
case 'i':
input = argv[2];
status_in = if_fifo(input);
break;
case 'o':
output = argv[3];
status_out = if_fifo(output);
break;
case 'd':
del = atof(argv[4]);
break;
case '?':
printf("UKNOWN");
}
}
}
if(status_in == 1)
{
return fifo_in(input);
}
else
{
cout << "It isnt fifo!!" << endl;
}
return 0;
}
And sender:
struct data
{
char* message;
int size;
vector <times> prog;
}msg;
int if_fifo(char* name)
{
struct stat info;
int score = stat(name,&info);
if(S_ISFIFO(info.st_mode))
{
return 1;
}
else
{
return 0;
}
}
int fifo_out(char* name)
{
msg.message = "To jest to!!";
msg.size = sizeof(msg.message);
int pip;
pip = open(name, O_WRONLY);
if( pip == -1 )
{
perror("Error: open( ): ");
return 1;
}
write(pip,&msg,sizeof(msg));
return 0;
}
int main(int argc, char** argv) {
int c, status_out;
char* output;
if(argc < 3)
{
cout << "Za malo podanych parametrow" << endl;
return 1;
}
else
{
while ((c = getopt(argc, argv, "o:")) != -1)
{
switch (c)
{
case 'o':
output = argv[2];
status_out = if_fifo(output);
break;
case '?':
printf("UKNOWN");
}
}
}
if(status_out == 1)
{
return fifo_out(output);
}
return 0;
}
you cannot just send memory structures from one program to another. You have to do whats called 'serialization' ie convert the struct into a byte stream that represents the structure. There are many, many serialization techniques: ASN1/ Ber, XML, JSON, Google protocol buffs, roll your own.
Just so you know why this is. The field message in your struct is actually a pointer, when you send this pointer to another program it points to the same address but in the receiver prgram not the sender. That address likely doesnt exist and certainly does not contain the string you had in the sender program.

getopt_long treat option name as argument

I was using getopt_long read command line options. code:
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
int ch;
struct option longopts[] = {
{"password", required_argument, NULL, 'p'},
{"viewonly", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
while ((ch = getopt_long(argc, argv, "p:vh", longopts, NULL)) != -1) {
switch (ch) {
case 'p':
printf("optarg: %x %s\n", optarg, optarg);
break;
case 'v':
printf("viewonly is set\n");
break;
case 'h':
case '?':
default:
fprintf(stderr, "error\n");
exit(EXIT_FAILURE);
}
}
return 0;
}
and I using this command line option: ./a.out --password --viewonly, It's supposed to print error message that --password is missing argument, but getopt_long never return '?', but treat --viewonly as the optarg of --password. and the output is:
optarg: 24992bc4 --viewonly
I think it's strange, and what should I do to prevent getopt_long treat option name as argument?
I would have some error checking in my switch statement (maybe check that a password cannot start with '--')

Segmentation fault - Core Dumped error while using getopt

I know this queston has been asked multiple times, but still I am unable to figure this out
#include<stdio.h>
#include<getopt.h>
int ch;
int queue_time=60;
int thread_num=4;
char *scheduling_algo="FCFS";
extern char *optarg;
int port=8080;
int debug_flag,h_flag,l_flag;
int main(int argc,char *argv[])
{
while ((ch = getopt(argc, argv, "dhlprtns")) != -1)
switch(ch)
{
case 'd':
debug_flag=atoi(optarg); /* print address in output */
break;
case 'h':
h_flag=atoi(optarg);
break;
case 'l':
l_flag=atoi(optarg);;
break;
case 'p':
port = atoi(optarg);
break;
case 'r':
printf("%s",optarg);
break;
case 't':
queue_time = atoi(optarg);
break;
case 'n':
thread_num = atoi(optarg);
break;
case 's':
scheduling_algo = optarg;
break;
default:
printf("nothing was passed");
}
printf("%d",queue_time);
printf("%d",debug_flag);
printf("%d",h_flag);
printf("%d",l_flag);
}
I am executing my program using the following command
./a.out -d -h -l -t 55
I am getting the core dumped error . I read a few examples on google, but still I am facing this problem. Can anyone please help?
You need to read the man page for getopt()
while ((ch = getopt(argc, argv, "dhlprtns")) != -1)
^^^^^^^^
This does not correspond to the way you are using the arguments. You
want colons ":" after the flags which expect arguments. In your code
"d" is not followed by a colon and yet you seem to want an value for it:
case 'd':
debug_flag=atoi(optarg); /* print address in output */
break;
So what is happening is you are calling atoi(0) and this is seg faulting.
Here's the example from the man page, note how "b" is not followed by a
colon while "f" is.
#include <unistd.h>
int bflag, ch, fd;
bflag = 0;
while ((ch = getopt(argc, argv, "bf:")) != -1) {
switch (ch) {
case 'b':
bflag = 1;
break;
case 'f':
if ((fd = open(optarg, O_RDONLY, 0)) < 0) {
(void)fprintf(stderr,
"myname: %s: %s\n", optarg, strerror(errno));
exit(1);
}
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
This may be of use to others: You will also get a segfault if you specify an option letter as both without colon, and with colon eg "dabcd:e" - in this case "d" occurs with and without colon.... and then use that option letter.
It appears getopt and its variants do not check for this conflict and return an error!

Getopt joining parameters

Is there way using getopt function to parse:
./prog -L -U
as same as:
./prog -LU
This is my try (not working):
while ((c = getopt(argc, argv, "LU")) != -1) {
switch (c) {
case 'L':
// L catch
break;
case 'U':
// U catch
break;
default:
return;
}
}
In this simple example are only 2 parameters but in my project are required all combinations of 6 parameters. For example: -L or -LURGHX or -LU -RG -H etc.
Can getopt() handle this? Or I must write complex parser to do that?
Save for a missing brace, your code works fine for me:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
int c;
while ((c = getopt(argc, argv, "LU")) != -1) {
switch (c) {
case 'L':
// L catch
printf("L\n");
break;
case 'U':
// U catch
printf("U\n");
break;
default:
break;
}
}
return 0;
}
$ ./a.out -LU
L
U
$ ./a.out -L
L
$
It behaves exactly as you would like:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv)
{
int c;
while ((c = getopt(argc, argv, "LU")) != -1) {
switch (c) {
case 'L':
puts("'L' option");
break;
case 'U':
// U catch
puts("'U' option");
break;
default:
puts("shouldn't get here");
break;
}
}
return 0;
}
And test it:
precor#burrbar:~$ gcc -o test test.c
precor#burrbar:~$ ./test -LU
'L' option
'U' option
precor#burrbar:~$ ./test -L -U
'L' option
'U' option
getopt() is a POSIX standard function that follows the POSIX "Utiltiy Syntax Guidelines", which includes the following:
Guideline 5:
Options without option-arguments should be accepted when grouped behind one '-' delimiter.
getopt does seem capable of handling it, and it does
Here are some examples showing what this program prints with different combinations of arguments:
% testopt
aflag = 0, bflag = 0, cvalue = (null)
% testopt -a -b
aflag = 1, bflag = 1, cvalue = (null)
% testopt -ab
aflag = 1, bflag = 1, cvalue = (null)

In C++, how to use only long options with a required argument?

In a C++ program, I would like to have a "long-only" option with a required argument. Below is my minimal example using getopt_long(), but it's not working:
#include <getopt.h>
#include <cstdlib>
#include <iostream>
using namespace std;
void help (char ** argv)
{
cout << "`" << argv[0] << "` experiments with long options." << endl;
}
void parse_args (int argc, char ** argv, int & verbose, int & param)
{
int c = 0;
while (1)
{
static struct option long_options[] =
{
{"help", no_argument, 0, 'h'},
{"verbose", required_argument, 0, 'v'},
{"param", required_argument, 0, 0}
};
int option_index = 0;
c = getopt_long (argc, argv, "hv:",
long_options, &option_index);
cout << "c=" << c << endl;
if (c == -1)
break;
switch (c)
{
case 0:
if (long_options[option_index].flag != 0)
break;
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case 'h':
help (argv);
exit (0);
case 'v':
verbose = atoi(optarg);
break;
case 'param':
param = atoi(optarg);
break;
case '?':
abort ();
default:
abort ();
}
}
}
int main (int argc, char ** argv)
{
int verbose = 0;
int param = 0;
parse_args (argc, argv, verbose, param);
cout << "verbose=" << verbose << " param=" << param << endl;
return EXIT_SUCCESS;
}
I compile it with this command (gcc version 4.1.2 20080704 Red Hat 4.1.2-46):
g++ -Wall test.cpp
It tells me this:
test.cpp:44:10: warning: character constant too long for its type
And here is the result:
$ ./a.out -v 2 --param 3
c=118
c=0
option param with arg 3
c=-1
verbose=2 param=0
I tried to make it work on ideone but it doesn't even recognize the option -v.
As indicated by trojanfoe in his comments of another question, it should be possible to use "long-only" options because GNU tar does it. However, GNU tar uses argp and I have difficulty understanding its source code.
Could someone give me a minimal example that works, with GNU getopt_long() or argp()?
There are two problems:
According to the example code (your link), the final option defined in the struct must be {0,0,0,0}. I recommend changing the definition to
static struct option long_options[] =
{
{"help", no_argument, 0, 'h'},
{"verbose", required_argument, 0, 'v'},
{"param", required_argument, 0, 0},
{0,0,0,0}
};
(And more importantly,) you must include code that actually processes the "param" option. You do that in the '0' case:
case 0:
if (long_options[option_index].flag != 0)
break;
if (strcmp(long_options[option_index].name,"param") == 0)
param = atoi(optarg);
break;
As you can see I use the strcmp function to compare the strings; for that you need to #include <cstring>. By the way, you also need #include <cstdio> for your use of printf.
With these changes in place, the program worked correctly for me (tested on GCC 4.5.1).
In your case statement, you are using:
case 'param':
which is giving you the warning, because compiler expects a single character in that place.
In fact, I realized that I should check the value of option_index when c has the value 0, like this. Such a case is not in the GNU libc examples, so here it is:
switch (c)
{
case 0:
if (long_options[option_index].flag != 0)
break;
if (option_index == 2)
{
param = atoi(optarg);
break;
}
case 'h':
help (argv);
exit (0);
case 'v':
verbose = atoi(optarg);
break;
case '?':
abort ();
default:
abort ();
}
Another solution is to use 'flag' member value defined in struct option.
Setup your options like below:
int param_flag = 0;
{"param", required_argument, &param_flag, 1}
Then;
case 0:
if (param_flag == 1) {
do_something;
}
See man getopt_long for details about struct option.