Using getopt in C for command line arguments - c

I am working on trying to take in command line arguments. If I want to have multiple optional command line arguments how would I go about doing that? For example you can run the program in the following ways:
(a is required every instance but -b -c -d can be given optionally and in any order)
./myprogram -a
./myprogram -a -c -d
./myprogram -a -d -b
I know that getopt()'s third argument is options. I can set these options to be "abc" but will the way I have my switch case set up causes the loop to break at each option.

The order doesn't matter so far as getopt() is concerned. All that matters is your third argument to getopt() (ie: it's format string) is correct:
The follow format strings are all equivalent:
"c:ba"
"c:ab"
"ac:b"
"abc:"
In your particular case, the format string just needs to be something like "abcd", and the switch() statement is properly populated.
The following minimal example¹ will help.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main (int argc, char **argv)
{
int aflag = 0;
int bflag = 0;
char *cvalue = NULL;
int index;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "abc:")) != -1)
{
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
¹Example taken from the GNU manual

Related

Why is getopt's optarg variable zero during debugging?

I noticed during debugging that the optarg variable of GNU's getopt remained zero (i.e. address 0x0) during debugging. But when optarg is used as right-hand operand of assignment or passed as argument to a parameter, the expected value is applied. The example from GNU:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main (int argc, char **argv)
{
int aflag = 0;
int bflag = 0;
char *cvalue = NULL;
int index;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "abc:")) != -1)
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c': # b 26
cvalue = optarg; # gdb stops right before executing this line
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
Usage
$ gcc -o getopt getopt.c -g # debugging ON, optimizations OFF
$ gdb getopt
(gdb) b 26 # set breakpoint
(gdb) r -cfoo
(gdb) p optarg
$1 = 0x0 # no "foo"?
(gdb) n # executes cvalue = optarg
(gdb) p cvalue
$2 = 0x7fffffffea99 "foo" # here it is, please don't expect to get the same memory-address
Why optarg doesn't contain the character string "foo" at line 26? What do I miss here?
More bewildering, I figured out it doesn't contain "foo" even after the line has been executed. I've put a glance at the original source and didn't notice something like a compiler optimization. I'm using GCC 11.1.0 on Archlinux, x86_64.
Thank you
PaulMcKenzie seems right. It is probably this old bug 8588 within GDB. GDB struggles handling the GOT (Global-Offset-Table) right which is a part of PIC (Position-Independent-Code].
Workaround
p (char*)'optarg#GLIBC_2.2.5'
We reference here the variable optarg and the version symbol of the GLIBC. The version 2.2.5 is the baseline which already includes provides GNU getopt and therefore the newer ones don't apply.
Thank you

Multiple integer arguments with getopt?

What is the best way to handle multiple integer arguments while using getopt? I have to be able to enter something like this on the command line: calc -a 100 50 and it will add up 100 and 50.
while ((opt = getopt(argc, argv, "adms")) != -1)
{
value = atoi(argv[optind + 1]);
printf("value : %d\n", value);
switch (opt)
{
case 'a': aFlag = 1; num1 = atoi(argv[optind]);
sum = num1 + value;
printf("%d + %d = %d\n" , num1, value, sum);
break;
case 'd': dFlag = 1;
break;
case 'm': break;
case 's': break;
default:
fprintf(stderr, "%s: unknown option %c\n", argv[0], optopt);
return 1;
}
}
if (aFlag == 1)
{
num1 = atoi(argv[optind]);
sum = num1 + value;
printf("%d + %d = %d\n" , num1, value, sum);
}
if (dFlag == 1)
{
num2 = atoi(argv[optind]);
sub = num2 / value;
printf("%d / %d = %d\n" , num2, value, sum);
}
I think that the interface you're after is probably:
./program -a 100 50
which accepts a single option -a (alternatives -m, -s and -d), and then processes the other arguments as a list of numbers, rather than as values attached to the option. This works fine unless you planned to be able to use:
./program -a 100 50 -m 20 30
to do addition and multiplication.
What do you want to do if someone can't make their mind up and tries:
./program -am 100 50
Should it be an error, or should -a or -m win? You can argue for any of those with some degree of coherency. I'd go with an error, though.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static int op_add(int a, int b) { return a + b; }
static int op_sub(int a, int b) { return a - b; }
static int op_mul(int a, int b) { return a * b; }
static int op_div(int a, int b) { return a / b; }
int main(int argc, char **argv)
{
int (*fun)(int, int) = 0;
char op;
int opt;
while ((opt = getopt(argc, argv, "adms")) != -1)
{
if (fun != 0)
{
fprintf(stderr, "%s: you can't use two operations\n", argv[0]);
return 1;
}
switch (opt)
{
case 'a': fun = op_add; op = '+'; break;
case 'd': fun = op_div; op = '/'; break;
case 'm': fun = op_mul; op = '*'; break;
case 's': fun = op_sub; op = '-'; break;
default:
fprintf(stderr, "%s: unknown option %c\n", argv[0], optopt);
return 1;
}
}
if (fun == 0 || optind + 2 != argc)
{
fprintf(stderr, "Usage: %s [-adms] num1 num2\n", argv[0]);
return 1;
}
int res = fun(atoi(argv[optind]), atoi(argv[optind+1]));
printf("%s %c %s = %d\n", argv[optind], op, argv[optind+1], res);
return 0;
}
The error checking on the values in the 'numeric' arguments is reprehensibly sloppy (meaning, non-existent). There's no division by zero check, either. But that at least produces plausible answers. It would probably be better to have an array of structures saving the function pointer and the operation character, but that sort of refinement is for you to deal with.
If you need a negative number, use -- to mark the end of the options:
$ ./program -m -- -39 -75
-39 * -75 = 2925
$
Just in case you're not sure about it, int (*fun)(int, int) is a pointer to a function that takes two int arguments and returns an int result. It allows the code to select which function to execute at runtime.
With getopt(), an option can take at most one argument. If you want your program to handle its command line with getopt(), and it must accept arguments such as you describe
calc -a 100 50
, and you must not repeat options, then the only viable solution is to make one or both of the integers non-option arguments instead of arguments to the -a option. I'd suggest making both (or all) non-option arguments. Thus, you might have something like this:
int result = getopt(argc, argv, "asmd");
switch (result) {
case 'a':
// careful: getopt() will be confused by negative numbers
if (getopt(argc, argv, "asmd") != -1) {
fprintf(stderr, "usage: %s -a|-s|-m|-d <operands>\n", argv[0]);
exit(1);
}
do_add(argv + optind);
break;
case 's':
// ...
}
After getopt() returns -1, optind is the index in argv one past that of the last option (+/- option argument) processed.
This excerpt from the man page for getopt() clearly shows that each of the answers (and the original question) are not showing an understanding of getopt:
optstring is a string containing the legitimate option characters.
If such a character is followed by a colon,
[then] 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.
your code should also allow for the following:
If getopt() does not recognize an option character,
it prints an error message to stderr,
stores the character in optopt,
and returns '?'.
and finally this (which will allow for the - to be in any position on the command line:
By default, getopt() permutes the contents of argv as it scans, so that
eventually all the nonoptions are at the end.

C getopt does not read all the parameters

I have an assignment in C that requires options to be read in for different forms of a program. Before I start on that, though, I want to make sure that the getopt portion is working fine. However, the program keeps dropping the last parameter and I don't know why. Whenever I enter the last char, the program goes to the default value that kills the program. Any help is appreciated!
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main(int argc, char **argv)
{
int sFlag = 0;
int lFlag = 0;
int dFlag = 0;
int rFlag = 0;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "slr:")) != -1)
{
switch(c)
{
case 's':
sFlag = 1;
break;
case 'l':
lFlag = 1;
break;
case 'r':
rFlag = 1;
break;
default:
printf("unknown parameter introduced");
exit(-1);
break;
}
}
printf("s = %i, l = %i, d = %i, r = %i", sFlag, lFlag, dFlag, rFlag);
return 1;
}
The colon symbol after r in "slr:" tells getopt() to wait for a mandatory argument which follows -r.
Examples:
getopt(argc, argv, "slr:") can parse ./project -s -l -r r_arg (or ./project -r r_arg -s etc.)
getopt(argc, argv, "s:lr:") can parse ./project -s s_arg -l -r r_arg
getopt(argc, argv, "s:lr:") can also parse ./project -s -l -r r_arg with no error, but the program works differently from user's expectation. This is because getopt() expects -s to be followed by its argument, however it looks like, so the next argument -l is consumed and will not hit your switch(c).

Getopt optional arguments?

I have a program where you enter an option
-d
and then whether or not you supply a non-optional argument after the option, do something.
Heres my code:
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#define OPT_LIST "d::"
int main (int argc, char *argv[])
{
int c;
char string[] = "blah";
while ((c = getopt (argc, argv, OPT_LIST)) != -1)
{
switch (c)
{
case 'd':
printf("%s\n", optarg);
break;
case '?':
fprintf(stderr, "invalid option\n");
exit(EXIT_FAILURE);
}
}
}
So if you enter a non-optional argument after the option, it prints the argument. But I want it to print out the char "string" if the user doesn't supply a non-optional argument (this is why I put the double colon in the
OPT_LIST). But I'm not sure how to do this so any help would be greatly appreciated.
Heres what happens when I run the program:
user:desktop shaun$ ./arg -d hello
hello
user:desktop shaun$ ./arg -d
./arg: option requires an argument -- d
invalid option
I'm running a Mac with OS X using C language.
The "optional value of an option" feature is only a GNU libc extension, not required by POSIX, and is probably simply unimplemented by the libc shipped with Mac OS X.
The options argument is a string that specifies the option characters that are valid for this program. 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.
https://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html
In fact, POSIX.1-2008, section 12.2, "Utility Syntax Guidelines", explicitly forbids this feature:
Guideline 7: Option-arguments should not be optional.
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02
According to the getopt documentation, it will return : if an option with an argument does not have one. It also sets optopt with the matching argument.
Therefore, use:
int main (int argc, char *argv[])
{
int c;
while ((c = getopt (argc, argv, ":d:f:")) != -1)
{
switch (c)
{
case 'd':
case 'f':
printf("option -%c with argument '%s'\n", c, optarg);
break;
case ':':
switch (optopt)
{
case 'd':
printf("option -%c with default argument value\n", optopt);
break;
default:
fprintf(stderr, "option -%c is missing a required argument\n", optopt);
return EXIT_FAILURE;
}
break;
case '?':
fprintf(stderr, "invalid option: -%c\n", optopt);
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
Maybe I'm misunderstanding the question. I'm reading it as though the user wants to over ride getopt's default error handling. If that is the case, shouldn't there be a : in the beginning of their OPT_LIST? I think the code above is good, however, I think it will still print
./arg: option requires an argument -- d
To surpress that, don't we need a : at the beginning of the OPT_LIST? For example, changing this:
while ((c = getopt (argc, argv, "d:f:")) != -1)
to this:
while ((c = getopt (argc, argv, ":d:f:")) != -1)
Correct me if I'm wrong.
Try this solution. It works for me. Consider option 'z' as option with optional argument.
int c;
opterr = 0; //if (opterr != 0) (which it is by default), getopt() prints its own error messages for invalid options and for missing option arguments.
while ((c = getopt (argc, argv, "x:y:z:")) != -1)
switch (c)
{
case 'x':
case 'y':
case 'z':
printf("OK ... option -%c with argument '%s'\n", c, optarg);
break;
case '?':
if (optopt == 'x' || optopt == 'y')
fprintf (stderr, "ERR ... Option -%c requires an argument.\n", optopt);
else if(optopt == 'z' && isprint(optopt))
{
printf("OK ... option '-z' without argument \n");
break;
}
else if (isprint (optopt))
fprintf (stderr, "ERR ... Unknown option `-%c'.\n", optopt);
else
fprintf (stderr, "ERR ... Unknown option character `\\x%x'.\n", optopt);
return -1;
default: ;
}
Here are some examples:
./prog -x
ERR ... Option -x requires an argument.
./prog -y
ERR ... Option -x requires an argument.
./prog -z
OK ... option '-z' without argument
./prog -x aaa
OK ... option -x with argument 'aaa'
./prog -y bbb -x aaa
OK ... option -y with argument 'bbb'
OK ... option -x with argument 'aaa'
./prog -x aaa -y bbb -z
OK ... option -x with argument 'aaa'
OK ... option -y with argument 'bbb'
OK ... option '-z' without argument
./prog -x aaa -y bbb -z ccc
OK ... option -x with argument 'aaa'
OK ... option -y with argument 'bbb'
OK ... option -z with argument 'ccc'

Reading command line arguments for flags and files C

Hello I'm new with C and I'm trying to start this lab where the command syntax is to first list any command line flags then list one or more file names.
I'm having trouble organizing how I want to scan the input arguments and differentiating them between flags and file names.
I thought of doing a loop to see if the argument is a flag or file name. But I'm unsure how to begin implementing it. Since the first 4 arguments can be potential flags in any order then anything after is the file name. But it is also possible for no flags to be given and just start with filenames. I don't know at all how to initalize this loop to go through each argument 1 by 1. Can anyone help please?
Example of possible command line arguments:
wc fcopy.c head.c (no flags given just file names)
wc -l -c -w -L fcopy.c head.c a.exe (flags given and multiple files)
wc -l -w -c -L fcopy.c (flags given and 1 file name)
Reading command line args one by one is pretty simple:
int main( int argc, // Number of strings in array argv char *argv[])
The two basic args to a C function are argc (int number of args), and argv (an array of strings for the args)
The first string is always the name of the program that is running, after that is the args that were passed over the command line.
if(argc > 1)
for( count = 1 count < argc; count++ )
printf("%s", argv[count]);
Will display to the screen each of the arguments passed in past the name of the calling program.
I assume your flags are passed with a "-" as the first character? If so, you can check the contents of the first character in each string for a '-' to tell if its a flag or not.
You can use getopt()
Check these questions:
Parsing command-line arguments?
Handling command line options before and after an argument in C
Argument-parsing helpers for C/UNIX
Getopt shift optarg
Check out getopt, it allows you to parse command line arguments and their flags:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argc, char **argv)
{
int aflag = 0;
int bflag = 0;
char *cvalue = NULL;
int index;
int c;
opterr = 0;
while ( (c = getopt (argc, argv, "abc:")) != -1 )
switch (c) {
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
Example of Parsing Arguments with getopt
Also see http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html

Resources