-
Notifications
You must be signed in to change notification settings - Fork 1
This portion of API presents basic extopts library functionality. Here 'basic' means simpliest CLI use case - parsing command line arguments, extracting their parameters, leaving the rest to be handeled by programmer directly.
To use basic extopts
#include <extopts/extopts.h>
should be inserted into source files.
int extopts_get(int *argc, char *argv[], struct extopt *opts);
Process command line arguments.
This is main extopts function which parses command line arguments according to passed extopts description structures array.
It takes standard command line arguments starting from executable path in argv[0].
After processing argv will be rearranged so that:
-
all non-option arguments will be moved to the beginning of argv starting from 0th argument;
-
0th argument, path to application will be moved right after all non-option arguments followed by options and their arguments. It also will be stored to extpath variable.
-
Short form of application name (its basename) will be stored at 'extname'. In case of module execution it will be changed to format -.
-
value by argc address will contain number of these non-option arguments.
Example of argv organization before extopts_get():
and after:
This example can be implemented using following extopts description:
int opts_int;
bool opts_flag;
const char *opts_str;
struct extopt opts[] = {
{
.name_long = "int",
.name_short = 'i',
EXTOPT_ARG_INT("INT", &opts_int),
.desc = "int option description",
}, {
.name_long = "flag",
.name_short = 'f',
EXTOPT_NO_ARG(&opts_flag),
.desc = "boolean flag description",
}, {
.name_long = "string",
EXTOPT_ARG_STR("STR", &opts_str),
.desc = "string option description",
},
EXTOPTS_END
};
int extopts_get(int *argc, char *argv[], struct extopt *opts);
Arguments
-
argc
- number of command line arguments received by typical *main(int argc, char argv[]) function; -
argv
- command line arguments in format received by typical *main(int argc, char argv[]) function; -
opts
- extopts array.
Return
- 0 in case of successfull options parsing;
- error code otherwise.
void extopts_usage(struct extopt *opts);
Print extopts-based usage to stdout.
Output will be aligned according to option names, the result for example above will look like:
-i, --int INT int option description
--string STR string option description
-f, --flag boolean flag description
Arguments
-
opts
- extopts array.
struct extopt *extopt_find(char *opt_str, struct extopt *opts);
Find extopt structure by short or long option name.
This function can be used to tweak command line parsing by creating own implementation of extopts_get() function while keeping other extopts features like usage autogeneration working.
Arguments:
-
opt_str
- short or long name to find; -
opts
- extopts array.
Return
- pointer to corresponding extopt structure if found;
- NULL otherwise.
static char extopt_is_end(struct extopt opt);
Check if extopt structure is array terminator.
Useful for getting through all extopts in array since it can be not always statically defined.
Arguments:
-
opt
- extopt structure to check.
Return:
- true - if extopt is terminator;
- false - otherwise.
Note: it is mandatory that extopts descriptors array should always be ending with EXTOPTS_END struct.
struct extopt {
char *name_long;
char name_short;
char *desc;
/* Option argument */
bool has_arg;
char *arg_name;
enum extopt_argtype arg_type;
union {
void *addr;
const char **const_str;
bool *flag;
int (*setter)(struct extopt *opt, const char *arg);
} arg;
};
Option descriptor structure.
Fields
-
name_long
- long option string (e.g. '--help', '--version') -
name_short
- short option char (e.g. 'h', 'v') -
desc
- string with option description. Will be used during generating extopts usage. Lines will be breaked and aligned during output. -
has_arg
- indicator of whether option has required argument. -
arg_name
- name of option argument for usage generation. This string will appear in option description in form:-<name_short>, --<name_long> <arg_name> <desc>
For example:-s, --str STR This option sets string
-
arg_type
- type of option argument. This option determines the way argument will be parsed. For reference look argtype description. Depending onarg_type
value one of pointers inarg
union will be used. -
arg
- pointers union to place where parsed option argument value will be stored. Basically, user rarely needs to work with this field since same can be done with macros.-
addr
- most common addr type used for almost every argument type; -
const_str
- used for working with string arguments without typecast; -
flag
- pointer to boolean for no-argument extopts. If this option will be met in command line arguments then true will be written by this address; -
setter
- pointer to setter function in case of 'special' extopt type. When this option will be met setter functionint (*setter)(struct extopt *opt, const char *arg)
will be called. It must parsearg
argument string and return 0 in case of parsing success.
-
enum extopt_argtype {
EXTOPT_ARGTYPE_NO_ARG,
EXTOPT_ARGTYPE_SPECIAL,
EXTOPT_ARGTYPE_INT,
EXTOPT_ARGTYPE_LINT,
EXTOPT_ARGTYPE_LLINT,
EXTOPT_ARGTYPE_UINT,
EXTOPT_ARGTYPE_ULINT,
EXTOPT_ARGTYPE_ULLINT,
EXTOPT_ARGTYPE_FLOAT,
EXTOPT_ARGTYPE_DOUBLE,
EXTOPT_ARGTYPE_LDOUBLE,
EXTOPT_ARGTYPE_STR,
EXTOPT_ARGTYPE_CHAR,
};
Enumeration of possible extopt argument types.
Values
-
EXTOPT_ARGTYPE_NO_ARG
- option with no argument. After parsing extoptflag
field will contain true or false depending on whether option was found; -
EXTOPT_ARGTYPE_SPECIAL
- option with manual argument parsing. When met,setter
function will be called; -
EXTOPT_ARGTYPE_INT
- option with int type argument. It will be parsed withstrtol
and written byaddr
field address; -
EXTOPT_ARGTYPE_LINT
- option with long int type argument. It will be parsed withstrtol
and written byaddr
field address; -
EXTOPT_ARGTYPE_LLINT
- option with long long int type argument. It will be parsed withstrtoll
and written byaddr
field address; -
EXTOPT_ARGTYPE_UINT
- option with unsigned int type argument. It will be parsed withstrtoul
and written byaddr
field address; -
EXTOPT_ARGTYPE_ULINT
- option with unsigned long int type argument. It will be parsed withstrtoul
and written byaddr
field address; -
EXTOPT_ARGTYPE_ULLINT
- option with unsigned long long int type argument. It will be parsed withstrtoull
and written byaddr
field address; -
EXTOPT_ARGTYPE_FLOAT
- option with flat type argument. It will be parsed withstrtof
and written byaddr
field address; -
EXTOPT_ARGTYPE_DOUBLE
- option with double type argument. It will be parsed withstrtod
and written byaddr
field address; -
EXTOPT_ARGTYPE_LDOUBLE
- option with long double type argument. It will be parsed withstrtold
and written byaddr
field address; -
EXTOPT_ARGTYPE_STR
- option with string type argument (const char*). Argument string pointer will be and written byconst_str
field address. Since it will point to string from argv itself, modifying it might be not the best idea - better to copy it somewhere else first. -
EXTOPT_ARGTYPE_CHAR
- option with char type argument (one-symbol strings). This char will be written byaddr
field address.
Following macro are designated to help with extopts structures
filling. It will handle has_arg
, arg_type
, arg
and sometime
name_long
and name_short
extopt fields. For more info look
argtype description.
This macros should be used insinde extopt function declaration.
For example:
struct extopt opts[] = {
{
.name_long = "int",
.name_short = 'i',
EXTOPT_ARG_INT("INT", &opts_int),
.desc = "int option description",
}, {
.name_long = "flag",
.name_short = 'f',
EXTOPT_NO_ARG(&opts_flag),
.desc = "boolean flag description",
}, {
.name_long = "string",
EXTOPT_ARG_STR("STR", &opts_str),
.desc = "string option description",
},
EXTOPTS_END
};
EXTOPT_ARG_INT(NAME, ADDR)
EXTOPT_ARG_LINT(NAME, ADDR)
EXTOPT_ARG_LLINT(NAME, ADDR)
Options with int, long int and long long int argument types. Argument is named NAME and will be parsed and written by address ADDR.
EXTOPT_ARG_UINT(NAME, ADDR)
EXTOPT_ARG_ULINT(NAME, ADDR)
EXTOPT_ARG_ULLINT(NAME, ADDR)
Options with unsigned int, unsigned long int and unsigned long long int argument types. Argument is named NAME and will be parsed and written by address ADDR.
EXTOPT_ARG_FLOAT(NAME, ADDR)
EXTOPT_ARG_DOUBLE(NAME, ADDR)
EXTOPT_ARG_LDOUBLE(NAME, ADDR)
Options with float, double and long double argument types. Argument is named NAME and will be parsed and written by address ADDR.
-
EXTOPT_ARG_STR(NAME, ADDR)
- option with const char* argument type. Argument is named NAME and target string pointer will be written by address ADDR. -
EXTOPT_ARG_CHAR(NAME, ADDR)
- option with char argument type. Argument is named NAME and will be written by ADDR.
-
EXTOPT_NO_ARG(FLAG_ADDR)
- option with no arguments. If it presents in command line arguments then true will be written by FLAG_ADDR address.
-
EXTOPT_ARG_SPECIAL(NAME, SETTER_FUNC)
- option with custom argument type. Argument is named NAME. Instead of parsing custom SETTER_FUNC handler will be called to process argument string.
This macros are designed to implement most commonly used command line options.
Unlike structure filling macros these group of macros present fully-defined extopt structures and not only part of it. So in extopts array declaration they can be used like:
struct extopt opts[] = {
{
.name_long = "int",
.name_short = 'i',
EXTOPT_ARG_INT("INT", &opts_int),
.desc = "int option description",
}, {
.name_long = "string",
EXTOPT_ARG_STR("STR", &opts_str),
.desc = "string option description",
},
EXTOPTS_HELP(&opts_help),
EXTOPTS_VERSION(&opts_version),
EXTOPTS_END
};
-
EXTOPTS_HELP(FLAG_ADDR)
- macro for defining standard help option. It will create no-arguments option-h, --help print this help and exit
and will write true by FLAG_ADDR address in case this option is present in command line arguments.
-
EXTOPTS_VERSION(FLAG_ADDR)
- macro for defining standard version option. It will create no-arguments option--version print version information and exit
and will write true by FLAG_ADDR address in case this option is present in command line arguments.
-
EXTOPTS_END
- extopts array terminator.
const char *extname;
Name of executable application. It is extracted from initial argv[0]
parameter with basename
function.
This variable is filled after extopts_get()
call.
const char *extpath;
Full path of executable application. It is extracted from initial argv[0] parameter.
This variable is filled after extopts_get()
call.
Extmods API allows to create CLI utility based on commands system: application firstly receives command name, then - arguments for it. Nearest example is git: git utility with commands commit, pull, push etc.
Functions of extmods group allow to easily implement such command
operation. Main utility can set its own policy of extracting command
name from command line arguments or use default with extmod_extract
function, parse arguments related to this command and pass rest of
arguments to main function of module, which is basically usual:
int func(int argc, char *argv[])
To use extmods functionality insert
#include <extopts/extmods.h>
into source files.
struct extmod *extmod_find(char *name);
Find extmod descriptor by name.
Arguments
-
name
- name of extmod to find.
Return
- pointer to extmod structure if found;
- NULL otherwise.
struct extmod *extmod_extract(int *argc, char *argv[]);
Extract module name from command line arguments. Default policy.
-
function checks if name of executable (argv[0]) presents one of registered extmods. This helps to implement busybox-like behaviour, when symbolic link 'cp' -> busybox' behaves like 'cp', 'ls' -> busybox' like 'ls' etc. If execname is found among modules - target extmod pointer returned.
-
if module cannot be enferred from executable name then first argument (argv[1]) is checked to contain one of modules. If it is then this argument is extracted from passed
argv
andargc
is decremented, corresponding extmod pointer returned. -
if argv[1] also not corresponds to one of module names then NULL is returned.
This function normally should not be used after extopts_get()
since
first one will mess with command line arguments in way not compatible
with extmods. The only exception is if you really know what you are
doing (because I don't).
Arguments
-
argc
- pointer to starndard argc argument usually got frommain(int argc, char *argv[])
function. Value may be decremented by 1 if module name was found in first command line argument; -
argv
- command line arguments frommain(int argc, char *argv[])
function. 1-st argument (argv[1]) may be extracted if it presentd module name (look above).
Return
- pointer to extmod descriptor structure if module found;
- NULL if no module was found.
int extmod_exec(int argc, char *argv[], struct extmod *module);
Execute module main()-function.
Arguments
-
argc
- number of command line arguments taken frommain(int argc, char *argv[])
; -
argv
- command line arguments taken frommain(int argc, char *argv[])
; -
module
- pointer to module to execute with specified command line arguments.
Return
- return code of module main()-function.
void extmod_print_desc(struct extmod *module);
Print module description specified in desc
extmod field.
Keyword [[OPTIONS]]
is replaced with output of extmod_print_opts()
function.
Arguments
-
module
- pointer to extmod descriptor structure.
void extmod_print_opts(struct extmod *module);
Print module options.
This function uses extopts feature to generate usage of module extopts if such were declared.
Arguments
-
module
- pointer to extmod descriptor structure.
bool extmod_has_name(struct extmod *module);
Check if extmod has name.
Arguments
-
module
- pointer to extmod descriptor structure.
Return
- true if module has name;
- false otherwise.
bool extmod_has_desc(struct extmod *module);
Check if extmod has description.
Arguments
-
module
- pointer to extmod descriptor structure.
Return
- true if module has description;
- false otherwise.
bool extmod_has_opts(struct extmod *module);
Check if extmod has extopts declared.
Arguments
-
module
- pointer to extmod descriptor structure.
Return
- true if module has extopts;
- false otherwise.
void extmods_usage_list(void);
Print aligned list of modules with their description.
struct extmod {
char *name;
int (*exec)(int argc, char *argv[]);
struct extopt *opts;
char *desc_short;
char *desc;
};
Extmod descriptor structure.
Fields
-
name
- module name; -
exec
- pointer to module main()-function. Prototype is identical to usualint main(int argc, char *argv[])
; -
opts
- array of module options described in form of extopts; -
desc_short
- description string used byextmods_usage_list()
function; -
desc
- full module description used byextmod_print_desc()
function.
Note: Normally this function is not instantiated manually since all modules must be composed into single array automatically. For this purposes macro is usually used.
#define EXTMOD_DECL(NAME, EXEC, OPTS, DESC_SHORT, DESC) \
struct extmod *extmod_##NAME; \
void extmod_constr_##NAME() __attribute__ ((constructor)); \
void extmod_constr_##NAME() \
{ \
extmod_##NAME = &extmods[extmods_num++]; \
extmod_##NAME->name = #NAME; \
extmod_##NAME->exec = EXEC; \
extmod_##NAME->opts = OPTS; \
extmod_##NAME->desc_short = DESC_SHORT; \
extmod_##NAME->desc = DESC; \
}
Macro for declaring extmod instance. It will automatically compose all module descriptors into single array before executing initial main() function.
-
NAME
- module name; -
EXEC
- module main() function; -
OPTS
- extopts array; -
DESC_SHORT
- short description forextmods_usage_list()
function; -
DESC
- full description forextmod_print_desc()
function.
struct extmod extmods[];
Array of declared with EXTMOD_DECL
extmod structures of size
extmods_num
.
int extmods_num;
Numerber of declared with EXTMOD_DECL
extmod structures.
struct extmod *extmod;
Currently executing module. Valid only inside of extmod_exec()
call. Outside it is NULL.
char extmodname[];
Name of currently executing module.
Has correct value only inside of extmod_exec()
call. Outside it is
NULL.
Module name is:
- module name, if application was executed busybox-style (look extmod_extract description),
- composed as "<app_name>-<module_name>" otherwise.