getopt_long problem - c

i have a problem with parsing arguments from a program that i'm writing, the code is below:
void parse_args(int argc, char** argv)
{
char ch;
int index = 0;
struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "port", required_argument, NULL, 'p' },
{ "stop", no_argument, NULL, 's' },
{ 0, 0, 0, 0 }
};
while ((ch = getopt_long(argc, argv, "hp:s", options, &index)) != -1) {
switch (ch) {
case 'h':
printf("Option h, or --help.\n");
break;
case 's':
printf("Option s, or --stop.\n");
break;
case 'p':
printf("Option p, or --port.\n");
if (optarg != NULL)
printf("the port is %s\n", optarg);
break;
case '?':
printf("I don't understand this option!!!\n");
case -1:
break;
default:
printf("Help will be printed very soon -:)\n");
}
}
}
When i run my program i got some strange output :
./Server -p 80
Option p, or --port.
the port is 80
./Server -po 80
Option p, or --port.
the port is o
./Server -por 80
Option p, or --port.
the port is or
./Server -hoho
Option h, or --help.
Server: invalid option -- o
I don't understand this option!!!

I think the confusion stems from a misunderstanding of long get opt. Essentially it will do partial string match only when you use the -- form. When you only use - it will fallback to standard parsing so -por 80 is matched as -p or 80 (as in, the option is -p and the argument is or). Try the same thing with --po and --por. As for help, try --he or--hel

Related

getopt_long()'s longindex always 0

In a C program I have to parse command line option for which I am using C function getopt_long() whose syntax is:
int getopt_long(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex);
Problem is I always receive the value of last parameter longindex as 0.
Below is the sample code:
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
static int verbose_flag;
int
main (int argc, char **argv)
{
int c;
printf("MAIN\n");
int i;
printf("argc = %d\n",argc);
for(i=0;i<argc;i++)
{
printf("argv[%d] = %s\n",i, argv[i]);
}
while (1)
{
static struct option long_options[] =
{
{"delete", required_argument, 0, 'd'},
{"create", required_argument, 0, 'c'},
{"file", required_argument, 0, 'f'},
{0, 0, 0, 0}
};
int option_index = 0;
c = getopt_long (argc, argv, "c:d:f:",
long_options, &option_index);
printf("\nOPT c = %d, option_index = %d START\n", c, option_index);
if (c == -1)
{
printf("BREAKKKKKKKKKKK\n");
break;
}
printf("OPTION FOUND c = %d, option_index = %d, long_options[option_index].name = %s\n", c, option_index, long_options[option_index].name);
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 'c':
printf ("option -c with value `%s'\n", optarg);
break;
case 'd':
printf ("option -d with value `%s'\n", optarg);
break;
case 'f':
printf ("option -f with value `%s'\n", optarg);
break;
case '?':
break;
default:
abort ();
}
}
if (verbose_flag)
puts ("verbose flag is set");
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
putchar ('\n');
}
return (0);
}
Output:
MAIN
argc = 5
argv[0] = /home/a.out
argv[1] = -delete
argv[2] = dell
argv[3] = -create
argv[4] = ceat
OPT c = 100, option_index = 0 START
OPTION FOUND c = 100, option_index = 0, long_options[option_index].name = delete
option -d with value `elete'
OPT c = 99, option_index = 0 START
OPTION FOUND c = 99, option_index = 0, long_options[option_index].name = delete
option -c with value `reate'
OPT c = -1, option_index = 0 START
BREAKKKKKKKKKKK
non-option ARGV-elements: dell ceat
Am I missing something?
Why do I always the value of last parameter longindex as 0?
How to rectify the issue?
From your argv[…] = … output it seems like you’re using long options incorrectly. Rather than invoke your program like this
/home/a.out -delete dell -create creat
Invoke it like this:
/home/a.out --delete dell --create creat
This will cause the index to be set correctly.
Check the getopt_long(3) manpage, section “Description”, for details on how to use long options.

Correct or decent getopts_long usage?

What it the correct usage if I want this behaviour:
$ ./a.out --help for printing help information
$ ./a.out --version for printing the program version
I managed to code this so that it takes the arguments but I don't know a good / correct way to separate the messages since they are the same case.
static struct option long_options[] = {
{"help", no_argument, 0, 0 },
{"version", no_argument, 0, 0 },
{0, 0, 0, 0 }
};
int main(int argc, char *argv[]) {
while (1) {
int this_option_optind = optind ? optind : 1;
int option_index = 0;
c = getopt_long(argc, argv, "",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
return 0;
case '0':
case '1':
case '2':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf("option 2 2 %c\n", c);
return 0;
case 'a':
printf("option a\n");
break;
case 'b':
printf("option b\n");
break;
case 'c':
printf("option c with value '%s'\n", optarg);
break;
case 'd':
printf("option d with value '%s'\n", optarg);
break;
case '?':
break;
default:
printf("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
...
Here you have an example:
while (1)
{
int option_index = 0;
static struct option long_options[] = {
{"with_param", required_argument, 0, 'p'},
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
option = getopt_long(argc, argv, "p:vh",
long_options, &option_index);
if (option == -1)
break;
switch (option) {
case 'p':
{
store_parameter(optarg);
break;
}
case 'v':
{
print_version();
break;
}
case 'h':
{
print_help();
exit(EXIT_SUCCESS);
break;
}
default:
{
fprintf(stderr, "Error (%s): unrecognized option.\n", __FUNCTION__);
print_help();
exit(EXIT_FAILURE);
break;
}
} /* end switch */
}
Notice the string "p:vh" as parameter of getopt_long, which allows you to also use short options. (":" follows options with a required argument)
You need to tell getopt_long the values it has to return:
static struct option long_options[] = {
{"help", no_argument, NULL, 1 },
{"version", no_argument, NULL, 2 },
{0, 0, 0, 0 }
};
Also, you could use "-h" as a synonym to "--help" and "-V" as a synonym to "--version", this would be done this way:
static struct option long_options[] = {
{"help", no_argument, NULL, 'h' },
{"version", no_argument, NULL, 'V' },
{0, 0, 0, 0 }
};
/* ... */
c = getopt_long(argc, argv, "abc:d:Vh", long_options, &option_index);
/* ... */
case 'h': // instead of case 1:
/* ... */
case 'V': // instead of case 2:
/* ...*/

c- parsing command line options with multiple arguments with getopt_long

I am new to c programming using command line arguments so despite finding few simmilar posts I am still stuck on this problem.
I need to pass a command line option that have more than 1 argument, for example
./testProgram --command arg1 arg2 arg3
here is my code
static struct option long_options[] = {
{"rdonly", required_argument, 0, 'a'},
{"wronly", required_argument, 0, 'b'},
{"command", required_argument, 0, 'c'},
{"verbose", no_argument, 0, 'd'},
{0,0,0,0}
};
c=getopt_long(argc,argv, "", long_options, &option_index);
if(c == -1)
break;
switch(c) {
case 'a':
rdonly(fd,optarg);
break;
case 'b':
wronly(fd,optarg);
break;
case 'c':
command(optind,optarg,argc,argv);
break;
case 'd':
printf("its verbose\n");
break;
default:
printf("WRONG OPTION\n");
}
}
//command function
int command(int optind, char *optarg, int argc, char* argv)
{
printf("Its option command with argument %s\n",optarg);
return 0;
}

Using getopt() and switch statements in C

I'm new to C and trying to use getopt combined with a switch statement. I think my problem is just a syntax one but I can't seem to figure it out. I need to run my program like this :
$/webserver -p 8080 -r /my/root/dir.
So I need to recognize the -p and get the 8080 and the recognize the -r and get the /my/root/dir. Currently my code finds the -p and then finds the -r and then detects an unknown option and exits. Here is the code. I have the puts() in there for testing.
#define USAGE_STRING "Usage: webserver -p <port> -r <rootdir>\n"
char *port;
char *rootdir;
// Process command line arguments. Uses GNU getopt() function.
void processargs(int argc, char **argv) {
int next_option;
do {
next_option = getopt(argc, argv, "pr:");
if (next_option != -1) {
switch (next_option)
{
case 'p': /* -p -- port option */
puts("p");
port = optarg;
printf("%s", port);
case 'r': // -r -- root directory option
puts("r");
rootdir = optarg;
printf("%s", rootdir);
default:
puts("unknown");
/* Unknown option detected. Print it to standard
output, and exit with exit code zero (normal termination). */
fprintf(stderr, USAGE_STRING);
exit(1);
}
}
} while (next_option != -1);
printf("%s", port);
if (port == NULL) {
fprintf(stderr, USAGE_STRING);
exit(1);
}
if (rootdir == NULL) {
puts("unknown");
fprintf(stderr, USAGE_STRING);
exit(1);
}
}
Currently when I run the above command I get this output (using the puts for testing).
p
r
unknown
Usage: webserver -p <port> -r <rootdir>
Thanks for any help!
I believe you want to use break at the end of each case, else execution falls through to the next case block.
A C switch statement requires a break at the end of each case, otherwise the code in the following case is executed. So this:
switch (next_option)
{
case 'p': /* -p -- port option */
puts("p");
port = optarg;
printf("%s", port);
case 'r': // -r -- root directory option
puts("r");
rootdir = optarg;
printf("%s", rootdir);
default:
puts("unknown");
/* Unknown option detected. Print it to standard output, and exit with exit code zero
(normal termination). */
fprintf(stderr, USAGE_STRING);
exit(1);
}
Must be changed to this:
switch (next_option)
{
case 'p': /* -p -- port option */
puts("p");
port = optarg;
printf("%s", port);
break;
case 'r': // -r -- root directory option
puts("r");
rootdir = optarg;
printf("%s", rootdir);
break;
default:
puts("unknown");
/* Unknown option detected. Print it to standard output, and exit with exit code zero
(normal termination). */
fprintf(stderr, USAGE_STRING);
exit(1);
}
First you should be using getopt_long() I believe getopt() is depreciated. You are also missing break in your switch statement. With out break each case beneath that one will be executed. While you could use a do-while loop it's simpler to just use a while loop.
Here's a simple command line parser you can build on.
static const char *optstring = "p:r:";
static struct option longopts[] =
{
{ "port", required_argument, NULL, 'p' },
{ "root", required_argument, NULL, 'r' },
{ NULL, 0, NULL, 0 }
};
int parseInput(int argc, char * const argv[])
{
int ch;
/* Main Loop ie the Parser */
while ((ch = getopt_long(argc, argv, optstring, longopts, NULL)) != -1)
{
switch(ch)
{
case 'p':
printf("arg: %s\n", optarg);
break;
case 'r':
printf("arg: %s\n", optarg);
break;
default:
printf("Unsupported option\n");
return -1;
}
}
return 0;
}

Getopt- Passing string parameter for argument

I have a program which takes in multiple command line arguments so I am using getopt. One of my arguments takes in a string as a parameter. Is there anyway to obtain that string through the getopt function or would I have to obtain it through the argv[] array? Also can getopt read args like -file ? All the arguments I have seen till now have only one character such as -a
EDIT
From the below answers I have written a program to use getopt_long(), but the switch statement only recognizes the argument when I use the character argument and not the long argument. I'm not sure why this happening. On passing the arguments -mf -file sample I do not see the print statements.
EDIT
I tried entering the command arguments as --file and then it worked. Is it not possible to do this with just -file ?
static struct option long_options[] =
{
{"mf", required_argument, NULL, 'a'},
{"md", required_argument, NULL, 'b'},
{"mn", required_argument, NULL, 'c'},
{"mw", required_argument, NULL, 'd'},
{"lf", required_argument, NULL, 'e'},
{"ld", required_argument, NULL, 'f'},
{"ln", required_argument, NULL, 'g'},
{"lw", required_argument, NULL, 'h'},
{"rf", required_argument, NULL, 'i'},
{"rd", required_argument, NULL, 'j'},
{"rn", required_argument, NULL, 'k'},
{"rw", required_argument, NULL, 'l'},
{"df", required_argument, NULL, 'm'},
{"dd", required_argument, NULL, 'n'},
{"dn", required_argument, NULL, 'o'},
{"dw", required_argument, NULL, 'p'},
{"file", required_argument, NULL, 'q'},
{NULL, 0, NULL, 0}
};
int ch=0;
while ((ch = getopt_long(argc, argv, "abcdefghijklmnopq:", long_options, NULL)) != -1)
{
// check to see if a single character or long option came through
switch (ch){
case 'a':
cout<<"title";
break;
case 'b':
break;
case 'c':
break;
case 'd':
break;
case 'e':
break;
case 'f':
break;
case 'g':
break;
case 'h':
break;
case 'i':
break;
case 'j':
break;
case 'k':
break;
case 'l':
break;
case 'm':
break;
case 'n':
break;
case 'o':
break;
case 'p':
break;
case 'q':
cout<<"file";
break;
case '?':
cout<<"wrong message"
break;
}
}
Read man getopt http://linux.die.net/man/3/getopt
optstring is a string containing the legitimate option characters. If
such a character is followed by a colon, the option requires an
argument, so getopt() places a pointer to the following text in the
same argv-element, or the text of the following argv-element, in
optarg. Two colons mean an option takes an optional arg; if there is
text in the current argv-element (i.e., in the same word as the option
name itself, for example, "-oarg"), then it is returned in optarg,
otherwise optarg is set to zero.
A sample code:
#include <stdio.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
int opt;
while ((opt = getopt (argc, argv, "i:o:")) != -1)
{
switch (opt)
{
case 'i':
printf("Input file: \"%s\"\n", optarg);
break;
case 'o':
printf("Output file: \"%s\"\n", optarg);
break;
}
}
return 0;
}
Here in the optstring is "i:o:" the colon ':' character after each character in the string tells that those options will require an argument. You can find argument as a string in the optarg global var. See manual for detail and more examples.
For more than one character option switches, see the long options getopt_long. Check the manual for examples.
EDIT in response to the single '-' long options:
From the man pages
getopt_long_only() is like getopt_long(), but '-' as well as "--" can indicate a long option. If an option that starts with '-'
(not "--") doesn't match a long option, but does match a short option,
it is parsed as a short option instead.
Check the manual and try it.
To specify that a flag requires an argument, add a ':' right after the flag in the short_opt variable. To use long arguments, use getopt_long().
Here is a quick example program:
#include <getopt.h>
#include <stdio.h>
int main(int argc, char * argv[]);
int main(int argc, char * argv[])
{
int c;
const char * short_opt = "hf:";
struct option long_opt[] =
{
{"help", no_argument, NULL, 'h'},
{"file", required_argument, NULL, 'f'},
{NULL, 0, NULL, 0 }
};
while((c = getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1)
{
switch(c)
{
case -1: /* no more arguments */
case 0: /* long options toggles */
break;
case 'f':
printf("you entered \"%s\"\n", optarg);
break;
case 'h':
printf("Usage: %s [OPTIONS]\n", argv[0]);
printf(" -f file file\n");
printf(" -h, --help print this help and exit\n");
printf("\n");
return(0);
case ':':
case '?':
fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
return(-2);
default:
fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c);
fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
return(-2);
};
};
return(0);
}

Resources