getopt_long() -- proper way to use it? - c

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 ;)

Related

Replace `?` key with `h` key in GNU argp

I'm using the argp.h library to parse command line arguments for my program.
I setup it a little and works, but there is just a thing I don't like.
When I run my program with --help it show this:
-?, --help Give this help list
--usage Give a short usage message
-V, --version Print program version
Which is correct, but why the short for --help is -?? Is it possible to specify a different key, like -h with a macro maybe?
I took a look at the docs but I didn't find any info about this, except maybe define a custom key, but I don't like this approach or better, I don't know if this is the preferred way.
Some digging around reveals the location in which '?' is defined as the short option for the default help functionality.
Without getting too lost in the source, it appears that when the default help is enabled, the user's argp and default argp (and if applicable, the version argp) are grouped together as siblings (see also: children), and then the program arguments are parsed. There does not appear to be an interface for changing the default values before this occurs, as the short option is hard coded.
Turning off the default help / usage options is possible by passing the ARGP_NO_HELP flag to argp_parse.
argp_state_help can be used to replicate the behaviour of the default options, using various flags. The flags used by the default options are:
--help: ARGP_HELP_STD_HELP
--usage: ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK
Where ARGP_HELP_EXIT_OK results in exit(0).
If not using argp_program_version_hook the behaviour of --version is to simply print argp_program_version.
A rough example:
#include <argp.h>
#include <stdio.h>
#include <stdlib.h>
#define USAGE 0x123
const char *argp_program_version = "example 1.0";
const char *argp_program_bug_address = "<so#example.com>";
static struct argp_option options[] = {
{ "help", 'h', 0, 0, "show this message", -1 },
{ "version", 'V', 0, 0, "show version", -1 },
{ "usage", USAGE, 0, 0, "show usage", 0 },
{ 0 }
};
static error_t parse_opt(int key, char *arg, struct argp_state *state)
{
switch (key) {
case 'h':
argp_state_help(state, state->out_stream, ARGP_HELP_STD_HELP);
break;
case USAGE:
argp_state_help(state, state->out_stream, ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
break;
case 'V':
fprintf(state->out_stream, "%s\n", argp_program_version)
exit(0);
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
int main(int argc, char **argv)
{
struct argp argp = { options, parse_opt };
argp_parse(&argp, argc, argv, ARGP_NO_HELP, 0, NULL);
}

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}
};

In C, how would I tell argp what to do if no option is passed?

Mods, please do not shoot this down, as I have been searching in every nook and cranny of Google for a solution in my free time over the past week or so and have still come up with nothing.
I've been working on learning C. You can find the entire project pertaining to this question here, although many other programs may want to be able to have an answaer as well:
https://github.com/Christoffen-Corporation/logo-generator
but this question primarily concerns the file main.c. Here's the source:
#include <stdio.h>
#include <argp.h>
#include <cairo.h>
#include "include.h"
const char *argp_program_version = "The Christoffen Corporation Logo Generator v2.0.1";
const char *argp_program_bug_address = "M. Gage Morgan <gage#christoffen.com>";
static char doc[] = "Generates all of the logo, or just some.";
static int parse_opt (int key, char *arg, struct argp_state *state) {
switch (key) {
case 'C':
colored_nologo();
break;
case 'c':
colored_all();
break;
case 'O':
outlined_nologo();
break;
case 'o':
outlined_all();
break;
case 'F':
frankenlogos();
break;
case 'a':
all_imgs();
}
return 0;
}
int main (int argc, char **argv) {
struct argp_option options[] =
{
{ "colored-no-logo", 'C', 0, 0, "Generate all colored triangles, except for the logo\n"},
{ "colored-all", 'c', 0, 0, "Generate all colored triangles, and the logo\n"},
{ "outlined-no-logo", 'O', 0, 0, "Generate all outlined triangles, except for the logo\n"},
{ "outlined-all", 'o', 0, 0, "Generate all outlined triangles, and the logo\n"},
{ "frankenlogos", 'F', 0, 0, "Generate the Frankenlogos (don't ask; just do)\n"},
{ "all-images", 'a', 0, 0, "Generate all images: Outlines, Colors, and Logos.\n"},
{ 0 }
};
struct argp argp = { options, parse_opt, 0, 0 };
return argp_parse (&argp, argc, argv, 0, 0, 0);
}
I have looked EVERYWHERE, and either I'm missing something right in front of me, or there is no way to get argp to have a "fallback" if no option is specified.
Any program that has command line options should be able to have a fallback if none is specified. In this case, for example, I wanted it to be able to either generate just seven triangles and a logo ("./logo-generator -c" or "./logo-generator -o"), or everything possible if nothing specified as an option ("./logo-generator")
I have a function titled all_imgs() that I'd like the program to fallback on when no options are specified. I know it sounds simple and at first I felt stupid for not knowing, but about 1.5 pages into 14 different Google queries, I realized that I wasn't going crazy and that there was no "if nothing specified do this" example.
By having the source available and the scenario, I really hope this is specific enough for one of you here at SO to figure out. If there is any other information I left out, please ask and I will be glad to give it to you. Also, if you absolutely need to know about functions I'm using in main.c, they can be found in options.c, which can be found in the GitHub repo above (<10 reputation disables me from putting it here, I mean no harm, swear).
I'm not asking you to re-write main.c and/or any other files. Specifically, this is a problem in main.c and no other files are affecting it. It compiles just fine, but I'm looking for a minimal change, not an entire re-write, of main.c. I'm asking for the SIMPLEST solution to this problem.
I appreciate your time.
--MGage
EDIT: I've added the source in as requested. I've checked the link added for "User Options," but I don't want to use arguments, and I don't understand what is so hard about that. Just options. I need the user to be able to specify an option if they want to generate only a portion of the images, and if not, then generate everything. Again, I don't want to re-write main.
FINAL EDIT: I don't know why I didn't realize this sooner, but the answer I marked correct WAS helpful. I apologize for making this difficult. The result was to add the conditional IF before the function started, give the desired function to argc, and then use ELSE to stick the desired part of argp I wanted into the program. To demonstrate, here's the final result (and it works!):
#include <stdio.h>
#include <argp.h>
#include <cairo.h>
#include "include.h"
const char *argp_program_version = "The Christoffen Corporation Logo Generator v2.0.1";
const char *argp_program_bug_address = "M. Gage Morgan <gage#christoffen.com>";
static char doc[] = "Generates all of the logo, or just some.";
static int parse_opt (int key, char *arg, struct argp_state *state) {
switch (key) {
case 'C':
colored_nologo();
break;
case 'c':
colored_all();
break;
case 'O':
outlined_nologo();
break;
case 'o':
outlined_all();
break;
case 'F':
frankenlogos();
break;
}
return 0;
}
int main (int argc, char **argv) {
if (argc == 1) {
all_imgs();
} else {
struct argp_option options[] =
{
{ "colored-no-logo", 'C', 0, 0, "Generate all colored triangles, except for the logo\n"},
{ "colored-all", 'c', 0, 0, "Generate all colored triangles, and the logo\n"},
{ "outlined-no-logo", 'O', 0, 0, "Generate all outlined triangles, except for the logo\n"},
{ "outlined-all", 'o', 0, 0, "Generate all outlined triangles, and the logo\n"},
{ "frankenlogos", 'F', 0, 0, "Generate the Frankenlogos (don't ask; just do)\n"},
{ 0 }
};
struct argp argp = { options, parse_opt, 0, 0 };
return argp_parse (&argp, argc, argv, 0, 0, 0);
}
}
Thanks, everyone. I know a lot of you reading this probably got frustrated with my boneheadedness.
You know that argc is the number of arguments passed, right? You don't need a library to count them. The first argument is always the name of the program, so you are looking for the case argc == 1.
int main(int argc, char **argv)
{
if (argc == 1) {
/* there are no extra arguments, handle this case */
} else {
/* there are arguments, proceed to parse and handle them */
}
}

error: invalid conversion from ‘void*’ to ‘arguments*’ [-fpermissive]

I am trying to study the examples of GNU C Library Code,to be specific, the usage of Argp and try it, but when I try
Argp-Example-3
Gcc hints me there is an error, but I do just copy the code from the web site. Here's the message?
argex.C: In function ‘error_t parse_opt(int, char*, argp_state*)’:
argex.C:92:45: error: invalid conversion from ‘void*’ to ‘arguments*’ [-fpermissive]
struct arguments *arguments = state->input;
^
argex.C: In function ‘int main(int, char**)’:
argex.C:138:30: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
arguments.output_file = "-";
^
argex.C is the file name.
It seems that I am converting 'void' to 'arguments'??
Thank you!
Heres the souce code
/* This program uses the same features as example 2, and uses options and
arguments.
We now use the first four fields in ARGP, so here's a description of them:
OPTIONS -- A pointer to a vector of struct argp_option (see below)
PARSER -- A function to parse a single option, called by argp
ARGS_DOC -- A string describing how the non-option arguments should look
DOC -- A descriptive string about this program; if it contains a
vertical tab character (\v), the part after it will be
printed *following* the options
The function PARSER takes the following arguments:
KEY -- An integer specifying which option this is (taken
from the KEY field in each struct argp_option), or
a special key specifying something else; the only
special keys we use here are ARGP_KEY_ARG, meaning
a non-option argument, and ARGP_KEY_END, meaning
that all arguments have been parsed
ARG -- For an option KEY, the string value of its
argument, or NULL if it has none
STATE-- A pointer to a struct argp_state, containing
various useful information about the parsing state; used here
are the INPUT field, which reflects the INPUT argument to
argp_parse, and the ARG_NUM field, which is the number of the
current non-option argument being parsed
It should return either 0, meaning success, ARGP_ERR_UNKNOWN, meaning the
given KEY wasn't recognized, or an errno value indicating some other
error.
Note that in this example, main uses a structure to communicate with the
parse_opt function, a pointer to which it passes in the INPUT argument to
argp_parse. Of course, it's also possible to use global variables
instead, but this is somewhat more flexible.
The OPTIONS field contains a pointer to a vector of struct argp_option's;
that structure has the following fields (if you assign your option
structures using array initialization like this example, unspecified
fields will be defaulted to 0, and need not be specified):
NAME -- The name of this option's long option (may be zero)
KEY -- The KEY to pass to the PARSER function when parsing this option,
*and* the name of this option's short option, if it is a
printable ascii character
ARG -- The name of this option's argument, if any
FLAGS -- Flags describing this option; some of them are:
OPTION_ARG_OPTIONAL -- The argument to this option is optional
OPTION_ALIAS -- This option is an alias for the
previous option
OPTION_HIDDEN -- Don't show this option in --help output
DOC -- A documentation string for this option, shown in --help output
An options vector should be terminated by an option with all fields zero. */
#include <stdlib.h>
#include <argp.h>
const char *argp_program_version =
"argp-ex3 1.0";
const char *argp_program_bug_address =
"<bug-gnu-utils#gnu.org>";
/* Program documentation. */
static char doc[] =
"Argp example #3 -- a program with options and arguments using argp";
/* A description of the arguments we accept. */
static char args_doc[] = "ARG1 ARG2";
/* The options we understand. */
static struct argp_option options[] = {
{"verbose", 'v', 0, 0, "Produce verbose output" },
{"quiet", 'q', 0, 0, "Don't produce any output" },
{"silent", 's', 0, OPTION_ALIAS },
{"output", 'o', "FILE", 0,
"Output to FILE instead of standard output" },
{ 0 }
};
/* Used by main to communicate with parse_opt. */
struct arguments
{
char *args[2]; /* arg1 & arg2 */
int silent, verbose;
char *output_file;
};
/* Parse a single option. */
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
/* Get the input argument from argp_parse, which we
know is a pointer to our arguments structure. */
struct arguments *arguments = state->input;
switch (key)
{
case 'q': case 's':
arguments->silent = 1;
break;
case 'v':
arguments->verbose = 1;
break;
case 'o':
arguments->output_file = arg;
break;
case ARGP_KEY_ARG:
if (state->arg_num >= 2)
/* Too many arguments. */
argp_usage (state);
arguments->args[state->arg_num] = arg;
break;
case ARGP_KEY_END:
if (state->arg_num < 2)
/* Not enough arguments. */
argp_usage (state);
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
/* Our argp parser. */
static struct argp argp = { options, parse_opt, args_doc, doc };
int
main (int argc, char **argv)
{
struct arguments arguments;
/* Default values. */
arguments.silent = 0;
arguments.verbose = 0;
arguments.output_file = "-";
/* Parse our arguments; every option seen by parse_opt will
be reflected in arguments. */
argp_parse (&argp, argc, argv, 0, 0, &arguments);
printf ("ARG1 = %s\nARG2 = %s\nOUTPUT_FILE = %s\n"
"VERBOSE = %s\nSILENT = %s\n",
arguments.args[0], arguments.args[1],
arguments.output_file,
arguments.verbose ? "yes" : "no",
arguments.silent ? "yes" : "no");
exit (0);
}
You should use a lowercase "c" for c files, i.e. argex.c, not argex.C. The uppercase C indicates a c++ file, and the implicit void* to anything conversion doesn't work in c++.
You could also add -x c to the command line (before the file name), but you really should use the correct extension.
To fix the implicit cast, if your compiling for c++, you also need to:
...
parse_opt (int key, char *arg, struct argp_state *state)
{
/* Get the input argument from argp_parse, which we
know is a pointer to our arguments structure. */
struct arguments *arguments = static_cast<struct arguments*>(state->input);
...
I am using the wrong file name. I should use ".c" but I missed using ".C".

C using getopt_long()

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.

Resources