Parse to integer with argp.h - c

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

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

syscall read acting weird

c lang, ubuntu
so i have a task - write a menu with these 3 options:
1. close program
2. show user id
3. show current working directory
i can only use 3 libraries - unistd.h, sys/syscall.h, sys/sysinfo.h.
so no printf/scanf
i need to use an array of a struct im given, that has a function pointer,
to call the function the user wants to use.
problem is on options 2 & 3;
when i pick 2, on the first time it works fine (i think)
second time i pick 2, it works, but then when going to the third iteration,
it doesn't wait for an input, it takes '\n' as an input for some reason, then it says invalid input. (i checked what it takes as input with printf, i printed index after recalculating it and it because -39, so it means selection[0] = 10 = '\n')
that's the first problem, that i just cant find the solution for.
second problem is on the current working directory function;
the SYS_getcwd returns -1 for some reason, which means there's an error, but i cant figure it out.
any explanations for these things?
(also - slen and __itoa are functions i am given - slen returns the length of a string,
__itoa returns a char*, that was the string representation of an integer)
helper.h:
typedef struct func_desc {
char *name;
void (*func)(void);
} fun_desc;
main.c:
#include <unistd.h>
#include "helper.h"
#include <sys/syscall.h>
#include <sys/sysinfo.h>
void exitProgram();
void printID();
void currDir();
int main() {
fun_desc arrFuncs[3];
arrFuncs[0].name = "exitProgram";
arrFuncs[0].func = &exitProgram;
arrFuncs[1].name = "printID";
arrFuncs[1].func = &printID;
arrFuncs[2].name = "currDir";
arrFuncs[2].func = &currDir;
char selection[2];
int index;
const char* menu = "Welcome to the menu. Please pick one of the following actions:\n1.Close the program\n2.Print the current user's id\n3.Print the current directory's id\n";
while(1 == 1) {
syscall(SYS_write, 0, menu, slen(menu));
syscall(SYS_write, 0, "Your selection: ", slen("Your selection: "));
syscall(SYS_read, 1, selection, slen(selection)); //might be a problem
selection[1] = '\0';
index = selection[0] - '0' - 1;
if(index > 2)
syscall(SYS_write, 0, "Invalid input\n", slen("Invalid input\n"));
else
arrFuncs[index].func();
}
return(0);
}
void exitProgram() {
syscall(SYS_write, 0, "The program will close\n", slen("The program will close\n"));
syscall(SYS_exit);
}
void printID() { //problem
char* uid = __itoa(syscall(SYS_getuid));
syscall(SYS_write, 0, uid, slen(uid));
syscall(SYS_write, 0, "\n", slen("\n"));
}
void currDir() { //????
char* buf = __itoa(syscall(SYS_getcwd));
syscall(SYS_write, 0, buf, slen(buf));
syscall(SYS_write, 0, "\n", slen("\n"));
}
You're passing the wrong number of arguments to some of these system calls. In particular:
syscall(SYS_exit);
_exit() takes one argument: the exit code.
char* buf = __itoa(syscall(SYS_getcwd));
getcwd() takes two arguments: a pointer to a buffer to write the string to, and the length of that buffer. In practice, this probably looks something like:
char pathbuf[PATH_MAX];
syscall(SYS_getcwd, pathbuf, sizeof(pathbuf));
If you don't have the header which defines PATH_MAX, define it yourself. 4096 is an appropriate value.
Note that getcwd() writes a string into the buffer passed to it — it does not return a numeric identifier.
As an aside, you may want to save yourself some time by implementing a wrapper to write a string, e.g.
void putstring(const char *str) {
syscall(SYS_write, 0, str, slen(str));
}
since you seem to be doing that a lot.

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".

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

parsing command option with default values and range constraints in C

I need to parse command line arguments in C. My arguments are basically
int or float with default values and range constrains.
I've started to implement something that look like this:
option_float(float* out, int argc, char* argv, char* name, description,
float default_val, int is_optional, float min_value, float max_value)
which I call for example with:
float* pct;
option_float(pct, argc, argv, "pct", "My super percentage option", 50, 1,
FALSE, 0, 100)
However I don't want to reinvent the wheel!
My objective is to have error checking of range constraints, throw an error when
the option is not optional and is not set. And generate the help message usually
given by usage() function.
The usage text would look like this:
--pct My super percentage option (default : 50). Should be in [0, 100]
I've started with getopt but it is too limited for what I want to do and I feel it still
requires me to write too much code for a simple use case like this.
What alternatives would you recommend?
Assuming you are coding for Linux...
Try getopt_long (man 3 getopt_long) for the double-dash options.
Also, try making the validators to be generic functions and let getopt/getopt_long to the hard part of the parsing and checking required arguments to options.
In any case, if you want to use your functions as defined, your example call will not work as defined.
A simplified example:
int main( int argc, char **argv )
{
float pct = 0.0
if( !GetArgs(argc, argv, &pct) )
DoStuff(pct)
}
int GetArgs( int argc, char **argv, float *thePct )
{
extern char *optarg;
int rc = 0;
(*thePct) = 50.0 /* default val */
while( (opt = getopt(argc, argv, "hp:")) != -1 )
{
switch( opt )
{
case 'p':
(*thePct) = atof( optarg );
break;
case 'h':
MyUsage(); /* Explain everything */
rc = -1;
break;
}
}
if( !rc )
{
rc = ValidatePct( (*thePct), /* value to check */
0.0, /* low pct val */
100.0 ); /* hi pct val */
/* Other validations here */
if( !rc )
MyUsage();
}
}
This will allow a call like:
$ myprogram -p 45.0
If you stick to the parsers getopt and getopt_long, you can also make command lines that take options followed by N number of other arguments like grep does, for instance:
grep -in -e "SomeRegex" file1, file2, ..., fileN
Out of sheer curiosity, you aren't a PERL programmer, are you?

Resources