Can't read arguments with getopt_long - c

I have the code below.
But when I run it with --debug=2, the debug variable gets value 100. I 'd expect 2...
Where is my mistake?
Here the code:
int debug=0;
int opt;
struct option longopts[] = {
{ "debug", required_argument, &debug, 'd' }
};
while ((opt = getopt_long(argc, argv, "d", longopts, NULL))!= -1)
{
switch (opt)
{
case 'd':
switch (debug)
{
case 1:
logPrio = LOG_INFO;
printf("1");
break;
case 2:
printf("2");
logPrio = LOG_CRIT;
break;
}
}
}
printf ("--%d--", debug);

Specifying &debug in longopts doesn't store the integer value of the option to the specified address, getopt_long expects you to extract integer values yourself.
According to the manual, the int *flag member of struct option does something completely different:
flag "specifies how results are returned for a long option. [If
non-NULL], getopt_long() returns 0, and flag points to a variable
which is set to val if the option is found, but left unchanged if
the option is not found.
You specify &debug for flag and 'd' for val, so debug gets set to 'd' (the number 100) when --debug is specified. Since you're already storing the result of getopt_long into the opt variable, you don't need to store &debug in longopts at all. Instead, use the optarg variable to get the argument to --debug:
case 'd':
debug = atoi(optarg);
switch (debug) {
...

Related

Dealing with non-option arguments in getopt before options are checked

I am writing a program and I want to get the non-option arguments before checking the flags.
For example, if the arguments are ./a.out -a -b 50 filename
I want to use filename and then do task_a() and/or task_b()depending on the flags. filename can be any argument in argv[]
int opt;
float value;
while ((opt = getopt(argc, argv, "ab:")) != -1)
case 'a':
task_a(filename);
break;
case 'b':
value = atof(optarg);
task_b(filename, value);
break;
So basically I need to extract filename before using it in my tasks. How can I implement this?
getopt will pass you the command line arguments in the order that it finds them on the command line. This is generally NOT the order that you want to process them.
Instead, have your program set its options first before performing the operations - so something like ( given #include <stdbool.h> ) :
// Set the defaults
bool doTaskA = false;
book doTaskB = false;
float brightness = -1;
int opt;
float value;
while ((opt = getopt(argc, argv, "ab:")) != -1) {
case 'a':
doTaskA = true;
break;
case 'b':
doTaskB = true;
brightness = atof(optarg);
break;
}
filename = ....,,
if (doTaskA) {
task_a(filename);
}
if (doTaskB) {
task_b(filename, brightness);
}
I chose the name “brightness” as a meaningful attribute name - naturally you should choose your own. As good practice, do NOT name your variables “optionA” or some such - variable names should describe what they ARE, not the specific implementation details.
Always imagine that your options can change letters over time (what is now option “a” might become option “R” in six months time) - such changes should not affect anything except the “getopt” arguments and “case” statements.
EDITED TO CHANGE :
I originally wrote this with “if (brightness >= 0.0)”, but decided that in general a separate doTaskB variable is cleaner, more explicit approach that does not limit the possible values of the argument.

get optarg with getopt

I have the following code:
char opt;
int bla1,bla2,bla3;
char *myarg = NULL;
while((opt = getopt(argc,argv,"a:b:cd")) != -1)
{
switch (opt)
{
case 'a':
bla1 = atoi(optarg);
break;
case 'b':
myarg = optarg;
break;
case 'c':
bla2 = 1;
break;
case 'd':
bla3 = 1;
break;
default:
break;
}
}
I want to be able to use optarg for case 'b' but in case none is selected to get a default value. Right now requires arg and cannot bypass it and if I replace "b:" with "b" it ignores the argument.
How can I make it work in both situations?
Some but not all versions of getopt allow you to indicate that an argument is optional by putting two colons after the relevant option character.
Wanting an optional argument to an option is a sign that your program is complicated enough that you should consider supporting long option names. Unfortunately there is no standard function to do this, but GNU libc has two: getopt_long and the even more powerful argp. If your software is GPL-compatible, you can get either of them from gnulib and then you don't depend on glibc.

What does "passing argument 2 of strcmp makes pointer from integer without a cast" error in C mean?

I am compiling my C code and am getting two errors:
warning:passing argument 2 of strcmp makes pointer from integer without a cast
and
warning: note: expected const char * but argument is of type int
This my main:
int main(int argc, char *argv[])
{
//check to make sure that the command line arguments are valid
if(argc!=3)
{
printf("invalid function call try again\n");
}
//else to choose the proper command
else
{
//reverse routine A
if(strcmp(argv[2],'a'||'A')==0) //line 138
{
reva(argv[1]);
}
//reverse routine B
else if(strcmp(argv[2],'b'||'B')==0) //line 143
{
revb(argv[1]);
}
//reverse routine C
else if(strcmp(argv[2],'c'||'C')==0) //line 148
{
revc(argv[1]);
}
//unacceptable command line argumant
else
{
printf("unacceptable command line argument for reverse routine try again:\n");
}
}
}
It means what it says. 'a'||'A' is an integer – specifically, it is the integer 1. The second argument of strcmp must be a string, not an integer.
You appear to intend to compare argv[2] to a and A. You need two different strcmp calls for that. Also, you need to use double, not single, quotes.
In "C", the '||' operator is a boolean 'or' operation, not a concatenation operation. Also, the use of apostrophes denotes a single character which basically 'char' type.
I think you want something like this (for line 148):
if (strcmp(argv[2], "C")==0 || (strcmp(argv[2], "c")==0) ...
or, if your C library supports it:
if (strcasecmp(argv[2], "C") == 0)
which is a case insensitive comparison.
I believe that your object here is to compare the command line argument (argv[2]) with the character (string) "C" or "c", ie you just if the user gave c or C at the command line.
The SO users have already offered an explanation. You need to use
(strcmp(argv[2], "C")==0 || (strcmp(argv[2], "c")==0)
in order to eliminate your warning.
However, this is not the optimal way to parse command line arguments in C. If your program is too complicated when parsing user input I would suggest to use the library "getopt". It is designed to help the user parse and analyze the input in a structured manner.
Here is a small code snipper
opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
while( opt != -1 ) {
switch( opt ) {
case 'I':
globalArgs.noIndex = 1; /* true */
break;
case 'l':
globalArgs.langCode = optarg;
break;
case 'o':
globalArgs.outFileName = optarg;
break;
case 'v':
globalArgs.verbosity++;
break;
case 'h': /* fall-through is intentional */
case '?':
display_usage();
break;
case 0: /* long option without a short arg */
if( strcmp( "randomize", longOpts[longIndex].name ) == 0 ) {
globalArgs.randomized = 1;
}
break;
default:
/* You won't actually get here. */
break;
}
opt = getopt_long( argc, argv, optString, longOpts, amp;longIndex );
}
Please search some documents (or the linux man pages) for getopt and getopt_long. Here is an example from GNU.

C switch question

I'm new to programming and I would like to add to a switch that would take in option cases such as -aa, -aaa, -aaaaaa etc where each of these three cases could serve a singular function in addition to case a?
I was thinking...
int option = getopt (argc, argv, "abcd");
switch(option){
case 'a': BLAH = TRUE;
break;
case 'b': FOO = TRUE;
break;
case 'c': BAR = TRUE;
break;
case 'd': BAZ = TRUE;
break;
}
for(int i = 1; i<argc; i++){
if ( argv[i][0] == '-' && argv[i][1] == 'a' && argv[i][i+2] == 'a' )
myOption =TRUE;
}
But would this work?
Thanks for reading.
The getopt_long(3) function provides command-line parsing to many programs, typically with invocations like this:
struct option long_options[] = {
{"add", 0, 0, 'a'},
{"binary", 0, 0, 'B'},
{"base", 1, 0, 'b'},
...
{"Optimize", 1, 0, 'O'},
{"preprocess", 0, 0, 'p'},
{NULL, 0, 0, 0},
};
while ((c = getopt_long(argc, argv, "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkO:po:", long_options, &o)) != -1)
{
switch (c) {
case 0:
PERROR("Assert, in getopt_long handling\n");
display_usage(progname);
exit(0);
break;
case 'a':
count++;
option = OPTION_ADD;
break;
case 'd':
debug++;
skip_read_cache = 1;
break;
/* ... and so forth */
You might be able to use getopt_long(3) to scan an array of inputs to look for multiple inputs (think add, binary, etc. from the long_options[]) that map to a single short option (a or B).
But if you are more specific about what you're trying to accomplish, there might be a better mechanism available.
No, this probably would not work. The best way in C (assuming you use Linux) is to use some of the getopt functions that the GNU C library provides. You could also use if..else if and strcmp() if you just need to process one or two long options.
Last time I checked similar features exist for BSD's libc as well (might be a bit different, though).
'aaa' is not integer, not char, and, not any type in the C language. The expression passed to switch statement should return an integer. So, switch statement is going to complain there.
For non integer comparisons such as the ones you have listed out, using if-else should be good.

getopt does not parse optional arguments to parameters

In C, getopt_long does not parse the optional arguments to command line parameters parameters.
When I run the program, the optional argument is not recognized like the example run below.
$ ./respond --praise John
Kudos to John
$ ./respond --blame John
You suck !
$ ./respond --blame
You suck !
Here is the test code.
#include <stdio.h>
#include <getopt.h>
int main(int argc, char ** argv )
{
int getopt_ret, option_index;
static struct option long_options[] = {
{"praise", required_argument, 0, 'p'},
{"blame", optional_argument, 0, 'b'},
{0, 0, 0, 0} };
while (1) {
getopt_ret = getopt_long( argc, argv, "p:b::",
long_options, &option_index);
if (getopt_ret == -1) break;
switch(getopt_ret)
{
case 0: break;
case 'p':
printf("Kudos to %s\n", optarg); break;
case 'b':
printf("You suck ");
if (optarg)
printf (", %s!\n", optarg);
else
printf ("!\n", optarg);
break;
case '?':
printf("Unknown option\n"); break;
}
}
return 0;
}
Although not mentioned in glibc documentation or getopt man page, optional arguments to long style command line parameters require 'equals sign' (=). Space separating the optional argument from the parameter does not work.
An example run with the test code:
$ ./respond --praise John
Kudos to John
$ ./respond --praise=John
Kudos to John
$ ./respond --blame John
You suck !
$ ./respond --blame=John
You suck , John!
The man page certainly doesn't document it very well, but the source code helps a little.
Briefly: you're supposed to do something like the following (though this may be a little over-pedantic):
if( !optarg
&& optind < argc // make sure optind is valid
&& NULL != argv[optind] // make sure it's not a null string
&& '\0' != argv[optind][0] // ... or an empty string
&& '-' != argv[optind][0] // ... or another option
) {
// update optind so the next getopt_long invocation skips argv[optind]
my_optarg = argv[optind++];
}
/* ... */
From among the comments preceding _getopt_internal:
...
If getopt finds another option character, it returns that character,
updating optind and nextchar so that the next call to getopt can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, getopt returns -1.
Then optind is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.) <-- a note from me:
if the 3rd argument to getopt_long starts with a dash, argv will not
be permuted
...
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in optarg. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in optarg, otherwise optarg is set to zero.
...
... though you have to do some reading between the lines. The following does what you want:
#include <stdio.h>
#include <getopt.h>
int main(int argc, char* argv[] ) {
int getopt_ret;
int option_index;
static struct option long_options[] = {
{"praise", required_argument, 0, 'p'}
, {"blame", optional_argument, 0, 'b'}
, {0, 0, 0, 0}
};
while( -1 != ( getopt_ret = getopt_long( argc
, argv
, "p:b::"
, long_options
, &option_index) ) ) {
const char *tmp_optarg = optarg;
switch( getopt_ret ) {
case 0: break;
case 1:
// handle non-option arguments here if you put a `-`
// at the beginning of getopt_long's 3rd argument
break;
case 'p':
printf("Kudos to %s\n", optarg); break;
case 'b':
if( !optarg
&& NULL != argv[optind]
&& '-' != argv[optind][0] ) {
// This is what makes it work; if `optarg` isn't set
// and argv[optind] doesn't look like another option,
// then assume it's our parameter and overtly modify optind
// to compensate.
//
// I'm not terribly fond of how this is done in the getopt
// API, but if you look at the man page it documents the
// existence of `optarg`, `optind`, etc, and they're
// not marked const -- implying they expect and intend you
// to modify them if needed.
tmp_optarg = argv[optind++];
}
printf( "You suck" );
if (tmp_optarg) {
printf (", %s!\n", tmp_optarg);
} else {
printf ("!\n");
}
break;
case '?':
printf("Unknown option\n");
break;
default:
printf( "Unknown: getopt_ret == %d\n", getopt_ret );
break;
}
}
return 0;
}
I recently came across this issue myself. I arrived at a similar solution to the one Brian Vandenberg and Haystack suggested. But to improve readability and avoid code duplication, you can wrap it all up in a macro like below:
#define OPTIONAL_ARGUMENT_IS_PRESENT \
((optarg == NULL && optind < argc && argv[optind][0] != '-') \
? (bool) (optarg = argv[optind++]) \
: (optarg != NULL))
The macro can be used like this:
case 'o': // option with optional argument
if (OPTIONAL_ARGUMENT_IS_PRESENT)
{
// Handle is present
}
else
{
// Handle is not present
}
break;
If you are interested, you can read more about how this solution works in a blog post I wrote:
https://cfengine.com/blog/2021/optional-arguments-with-getopt-long/
This solution is tested and is – at the time of this writing – currently used in CFEngine.
I also ran into the same problem and came here. Then I realised this .
You don't have much of a use case of "optional_argument" . If an option is required you check from program logic, if an option is optional then you need not do anything because at getopt level all options are optional , they are not mandatory, so there is no use case of "optional_argument". Hope this helps.
ps: for the above example i think the correct options are
--praise --praise-name "name" --blame --blame-name "name"

Resources