The flag parser generator.
It utilizes a simple syntax to generate command-line flag parsers written in C.
In order to build gonf using the provided Makefile, you need:
gcc # v10-2.1
flex # v2.6.4
xxd # v1.10
Any version of these programs should work, but I have written the ones I have been using just in case.
To build/debug use:
make # build with debug flags
make release # build with release flags
make run # build and run
make clean # clean the output directory
To install/uninstall (will only work on Linux)
sudo make release install # build with release flags & install
sudo make uninstall # uninstall
gonf [FLAGS]... [FILES]...
The list of all available flags can be seen by
using the --help
flag.
The program tries to compile the provided files (reads from stdin if none are present) into a C source file containing the generated parser.
The default output file name is 'gonf.c'
, but it can be changed with the --output
flag.
Additionaly, one can use the --header-file
option,
in order to generate a C header file for the generated parser.
The syntax can be quickly summarized as:
IDENTIFIER: -SHORTNAME --LONGNAME "DESCRIPTION" = "DEFAULT_VALUE";
...
where:
IDENTIFIER
is an alphanumeric string.SHORTNAME
is any ASCII character except';"=-\
.LONGNAME
is aSHORTNAME
followed by any string of characters except';"=\
.DESCRIPTION
is any string of characters exceptNUL
.DEFAULT_VALUE
is any string of characters exceptNUL
(has to be preceded by=
).
and where every part is optional except SHORTNAME
or LONGNAME
(at least one must be present) and a ;
separator.
...or expressed in Backus-Naur form:
<FLAGSPEC> ::= <FLAG> <FLAGSPEC> | <FLAG>
<FLAG> ::= <IDENTIFIER> <NAME> <DESCRIPTION> <VALUE> <SEPARATOR>
<IDENTIFIER> ::= <TEXT> ":" | ""
<NAME> ::= <SHORTNAME> <LONGNAME> | <SHORTNAME> | <LONGNAME>
<SHORTNAME> ::= "-" <CHAR>
<LONGNAME> ::= "--" <TEXT>
<DESCRIPTION> ::= <STRING> | ""
<VALUE> ::= "=" <STRING> | "=" | ""
<SEPARATOR> ::= ";"
<TEXT> ::= <CHAR> <TEXT> | <CHAR>
<CHAR> ::= ; any printable, non-whitespace char, except ';"=-\.
<STRING> ::= ; any string of characters (except NUL) enclosed in double quotes
The IDENTIFIER
, SHORTNAME
and LONGNAME
must be unique.
C-style comments can also be used:
//
for single-line,/* */
for multiline.
Whitespace outside double quotes is completely ignored.
Let's say you want to generate a flag parser recognizing the flags:
'help'
, abbreviated by'h'
, described as'Print help'
.'o'
, accepting some value.'skrzat'
, described as'psotnik'
, accepting a value that's initially set as'churbo'
.
A representant gonf file would then look like this:
-h --help "Print Help";
-o =;
--skrzat "psotnik" = "churbo";
Additionally, in order to have easier access to the flags in code, an identifier can be specified:
HELP: -h --help "Print Help";
OUTPUT: -o =;
MCFLUNGUS: --skrzat "psotnik" = "churbo";
Finally, you can add some comments:
HELP: -h --help "Print Help"; // single-line comment
OUTPUT: -o =;
/* multiline
comment
*/
MCFLUNGUS: --skrzat "psotnik" = "churbo";
The generated parser is a C source file containing various functions allowing one to:
- Check how many times a flag has appeared.
- Read the flag's shortname, longname or description.
- Read the flag's default and set value (if it has one).
- Obtain an array of every passed non-flag argument.
Provided are also functions allowing one to handle errors encountered when parsing.
An optional header file can be generated, containing declarations of every function and macro, as well as their descriptions.
The main parser function is called gonfparse
.
It scans the provided command-line arguments for the
specified flags, generating errors when:
- an unrecognized flag has been encountered.
- a value has been passed to a flag not accepting a value.
- no value has been provided for a value flag with no specified default value.
and returning an array of non-flag arguments.
Every flag is represented by gonflag
struct containing fields
such as:
char shortname;
char *longname;
char *description;
bool is_value;
char *default_value;
char *value;
gonfc_t count;
In order to then access a specific flag,
one needs to use the gonflag_get
family of functions.
Flags can be obtained by passing their:
- index (easily available with the
GONFLAG_INDEX
macro, when an identifier has been specified) - shortname (
gonflag_get_by_short
) - longname (
gonflag_get_by_long
)
Additional documentation as well as some helper macros are provided in the (optional) generated header file.
/* include the header file */
#include <gonf.h>
char **args;
/* parse flags */
args = gonfparse(argc, argv);
/* check for errors */
if(gonferror() != GONFOK){
gonferror_print();
return -1;
}
struct gonflag *flag;
/* Print a flag's name & description. */
flag = gonflag_get(GONFLAG_HELP);
printf("%c\n", flag->shortname);
printf("%s\n", flag->longname);
printf("%s\n", flag->description);
/* Print a flag's value. */
flag = gonflag_get(GONFLAG_INDEX(OUTPUT));
if(flag->count)
printf("%s\n", flag->value);
/* Print a flag's value using helper macros
* (will be set to default_value if none was provided).
*/
if(gonflag_is_present(GONFLAG_MCFLUNGUS))
printf("%s\n", gonflag_get_value(GONFLAG_MCFLUNGUS));
I appreciate any bug report/contribution/criticism.