C using getopt_long() - c

I have been reading how to use getopt_long(), and how to "Read" the multiple character options with optlong.
I need to parse the following entry from the terminal:
./bomb –n String –cp Integer –i Integer –c Integer –fc String
so before I use getoptlong, I define my short and long options:
if(argc != 11){
perror("Error en numero de argumentos \n");
exit(EXIT_FAILURE);
}
const char* const short_options = "n:i:c:";
static struct option long_options[] = {
{"cp", 1, NULL, 'a'},
{"fc", 1, NULL, 'b'},
{0, 0 , 0, 0}
};
my short_options pick up n with an argument (that is what the : is for), the same for c and i.
So the same should be applied for the long options (they both pick up arguments as well).
while(opt != -1){
opt = getopt_long(argc, argv, short_options, long_options, NULL);
switch (opt){
case 'n':
//print it
case 'a':
//print it
}
}
Now the thing is, this code works perfect for when it parses -c -i and -n , it enter the case it belongs to and prints correctly.
My issue, its not working for -cp and -fc. And really I have no idea how to fix this since I haven’t work with getopt() before.
thanks in advance

Quoting man getopt_long:
The getopt_long() function works like getopt() except that it also
accepts long options, started with two dashes.
and
getopt_long_only() is like getopt_long(), but - as well as -- can
indicate a long option.
So you should either use --cp and --fc, or switch to getopt_long_only.

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.

Parse to integer with argp.h

I would like to be able to receive program arguments and options in my C program. The options should be treated as floats or ints. For some reason, I couldn't find good articles, tutorials, docs about argp.h. I started my implementation with the examples on the GNU Libc Manual, though unfortunately, it didn't get me to the solution.
Here is how I tried to solve the problem (example can be compiled, included every necessary line):
#include <stdlib.h>
#include <argp.h>
static char doc[] = "Doc";
static char args_doc[] = "ARG1";
static struct argp_option options[] = {
{"bool", 'b', 0, 0, "Simple boolean flag, works as I expected."},
{"int", 'i', 0, 0, "Would like to be able to parse options as --int=4 or -i 4."}, // but I can't
{0}
};
struct arguments {char *args[1]; int xbool, xint;};
static error_t
parse_opt (int key, char *arg, struct argp_state *state) {
struct arguments *arguments = state->input;
printf("key = %c, arg = %s\n", key, arg); // My attempt to understand the problem
//if (arg == NULL) return 0; // Prevents segfaults, in order to see how the args and keys change
switch (key) {
case 'b': arguments->xbool = 1; break;
case 'i': arguments->xint = (int) strtol(arg, NULL, 10); break;
case ARGP_KEY_ARG: if (state->arg_num >= 1) {argp_usage(state);} arguments->args[state->arg_num] = arg; break;
case ARGP_KEY_END: if (state->arg_num < 1) {argp_usage(state);} break;
default: return ARGP_ERR_UNKNOWN;
}
return 0;
}
static struct argp argp = { options, parse_opt, args_doc, doc };
int main (int argc, char **argv) {
struct arguments arguments;
arguments.xbool = 0;
arguments.xint = 0;
argp_parse (&argp, argc, argv, 0, 0, &arguments);
printf("ARG1 = %s\nbool option = %s\nparsed int option = %d",
arguments.args[0], arguments.xbool ? "true" : "false", arguments.xint);
exit (0);
}
The simple boolean flag works, as expected, so ./myprogram.out myarg --bool and ./myprogram.out myarg -b changes the flag's value.
However, I can't seem to find a way to parse the arguments as integers or floating point numbers.
This it the output I get for ./a.out -b --int=2 myarg:
key = , arg = (null)
key = b, arg = (null)
./a.out: option '--int' doesn't allow an argument
Try `a.out --help' or `a.out --usage' for more information.
and for ./a.out -b --int 2 myarg I get a segmentation fault, as I try to parse a NULL: key = i, arg = (null). I added a NULL check, and this way I could see, that the option I would like to parse comes with a , key (expected to come with i).
key = i, arg = (null)
key = , arg = 2
I thought about using a library because the program needs to handle various float and int options, falling back to default values, and I've seen often that it's not recommended to roll your own argument and options parser. Based on the examples, argp.h looked promising, however I couldn't get it to work yet.
ps. I know that parsing directly to ints and floats are not part of argp, this is why I was (naively, it seems) trying to add it to the structures and parse_opt function.
As it turned out, there was an error with options[]. The third, const char *arg parameter in the argp_option struct must be provided, if the option has argument associated with it [source: GNU C: Argp Option Vectors].
static struct argp_option options[] = {
{"bool", 'b', 0, 0, "Simple boolean flag, works as I expected."},
{"int", 'i', "Numbah", 0, "Now everything works as expected, I get the correct key-value (key-arg) pair in the parse_opt function"},
{0}
};

getopt_long() -- proper way to use it?

OK, I have searched and found the following two StackOverflow topics that started me in the right direction:
Argument-parsing helpers for C/UNIX
Pass arguments into C program from command line
NOTE: ALL CODE IS PSEUDO-CODE. WILL POST COMPILABLE CODE WHEN IT WORKS.
However, I'm still completely confused on how to use getopt_long() in C. The program I'm writing is defined as having the following possible tags (but can include as many as you absolutely need, filling the rest in with empty values):
id3tagEd filename -title "title" -artist "artist" -year 1991 -comment "comment" -album "album" -track 1
Now, from what I read, I need to utilize a struct for the long options, correct? If so, I wrote something along the lines of this:
struct fields field =
{
char *[] title;
char *[] artist;
char *[] album;
int year;
char *[] comment;
int track;
}
static struct options long_options[] =
{
{"title", 0, &field.title, 't'},
{"artist", 0, &field.artist, 'a'},
{"album", 0, &field.album, 'b'},
{"year", 0, &field.year, 'y'},
{"comment", 0, &field.comment, 'c'},
{"track", 0, &field.track, 'u'},
{0, 0, 0, 0}
}
Now, from what I gathered, I would be calling it via this:
int option_index = 0;
int values = getopt_long(argc, argv, "tabycu", long_options, &option_index);
From here, could I strictly use the field struct and do what I need to within my program? However, if this is the case, can someone explain the whole long_options struct? I read the man pages and such, and I'm just utterly confused. By rereading the man pages, I can see I can set variables to null, and should be setting all my option requirements to "required_argument"? And then setting the structs via a while() loop? However, I see optarg being used. Is this set by getopt_long()? Or is it missing from the example?
And one last issue, I will always have an unnamed required option: filename, would I just use argv[0] to gain access to that? (Since I can assume it'll be first).
On a side note, this is related to a homework problem, but it has nothing to do with fixing it, its more of a fundamental, have to understand argument passing and parsing in C via command line first.
First off, you probably don't want 0 for the has_arg field - it must be one of no_argument, required_arguemnt, or optional_argument. In your case, all of them are going to be required_argument. Besides that, you're not using the flag field correctly - it has to be an integer pointer. If the corresponding flag is set, getopt_long() will fill it in with the integer you passed in via the val field. I don't think you need this feature at all. Here's a better (shortened) example for your case:
static struct option long_options[] =
{
{"title", required_argument, NULL, 't'},
{"artist", required_argument, NULL, 'a'},
{NULL, 0, NULL, 0}
};
Then later, you can use it appropriately (straight from the manpage, I added some comments):
// loop over all of the options
while ((ch = getopt_long(argc, argv, "t:a:", long_options, NULL)) != -1)
{
// check to see if a single character or long option came through
switch (ch)
{
// short option 't'
case 't':
field.title = optarg; // or copy it if you want to
break;
// short option 'a'
case 'a':
field.artist = optarg; // or copy it if you want to
break;
}
}
You can extend for your other fields as necessary (and add some error handling, please!). Note - if you want to use -title and -artist like you have in your example, you'll need to use getopt_long_only(), which doesn't have short options.
As to your filename option, you'll get that out as a '?' from the getopt_long() call, so you could handle it at that time. Your other options are to require that it is either the first or the last option and handle it by itself separately.
If you use the popt library, you will be able to create something smart as you did in your pseudo-code:
#include <stdio.h>
#include "popt.h"
struct _field {
char *title;
char *artist;
/* etc */
} field;
field.title = NULL;
field.artist = NULL;
/* HERE IS WHAT YOU WANTED IN YOUR PSEUDO-CODE */
struct poptOption optionsTable[] = {
{"title", 't', POPT_ARG_STRING, &field.title, 't'
"set the 'title' of the album" },
{"artist", 'a', POPT_ARG_STRING, &field.artist, 'a'
"set the 'artist' of the album" },
POPT_AUTOHELP
POPT_TABLEEND
};
poptContext optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
poptSetOtherOptionHelp(optCon, "[OPTIONS]");
char c;
while ((c = poptGetNextOpt(optCon)) >= 0) {
switch (c) {
case 't':
/* do extra stuff only if you need */
break;
case 'a':
/* do extra stuff only if you need */
break;
default:
poptPrintUsage(optCon, stderr, 0);
exit(1);
}
}
if (field.title) printf("\nTitle is [%s]", field.title);
if (field.artist) printf("\nArtist is [%s]", field.artist)
Be smart than getopt ;)

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