Skip to content
Dmitry Lavnikevich edited this page Aug 29, 2014 · 15 revisions

Extopts

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.

Functions

extopts_get

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:

  1. all non-option arguments will be moved to the beginning of argv starting from 0th argument;

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

  3. Short form of application name (its basename) will be stored at 'extname'. In case of module execution it will be changed to format -.

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

extopts_usage

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.

extopt_find

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.

extopt_is_end

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.

Types

extopt

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 on arg_type value one of pointers in arg 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 function int (*setter)(struct extopt *opt, const char *arg) will be called. It must parse arg argument string and return 0 in case of parsing success.

extopt_argtype

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 extopt flag 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 with strtol and written by addr field address;
  • EXTOPT_ARGTYPE_LINT - option with long int type argument. It will be parsed with strtol and written by addr field address;
  • EXTOPT_ARGTYPE_LLINT - option with long long int type argument. It will be parsed with strtoll and written by addr field address;
  • EXTOPT_ARGTYPE_UINT - option with unsigned int type argument. It will be parsed with strtoul and written by addr field address;
  • EXTOPT_ARGTYPE_ULINT - option with unsigned long int type argument. It will be parsed with strtoul and written by addr field address;
  • EXTOPT_ARGTYPE_ULLINT - option with unsigned long long int type argument. It will be parsed with strtoull and written by addr field address;
  • EXTOPT_ARGTYPE_FLOAT - option with flat type argument. It will be parsed with strtof and written by addr field address;
  • EXTOPT_ARGTYPE_DOUBLE - option with double type argument. It will be parsed with strtod and written by addr field address;
  • EXTOPT_ARGTYPE_LDOUBLE - option with long double type argument. It will be parsed with strtold and written by addr field address;
  • EXTOPT_ARGTYPE_STR - option with string type argument (const char*). Argument string pointer will be and written by const_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 by addr field address.

Macros

Extopt structure filling

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

Signed integer arguments

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

Unsigned integer arguments

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

Floating-point arguments

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

String arguments

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

No arguments

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

Special argument parser

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

Pre-defined extopt structures

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.

Global variables

extname

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.

extpath

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

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.

Functions

extmod_find

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.

extmod_extract

struct extmod *extmod_extract(int *argc, char *argv[]);

Extract module name from command line arguments. Default policy.

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

  2. 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 and argc is decremented, corresponding extmod pointer returned.

  3. 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 from main(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 from main(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.

extmod_exec

int extmod_exec(int argc, char *argv[], struct extmod *module);

Execute module main()-function.

Arguments

  • argc - number of command line arguments taken from main(int argc, char *argv[]);
  • argv - command line arguments taken from main(int argc, char *argv[]);
  • module - pointer to module to execute with specified command line arguments.

Return

  • return code of module main()-function.

extmod_print_desc

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.

extmod_print_opts

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.

extmod_has_name

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.

extmod_has_desc

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.

extmod_has_opts

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.

extmods_usage_list

void extmods_usage_list(void);

Print aligned list of modules with their description.

Types

extmod

  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 usual int main(int argc, char *argv[]);
  • opts - array of module options described in form of extopts;
  • desc_short - description string used by extmods_usage_list() function;
  • desc - full module description used by extmod_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.

Macros

Extmod declaration

  #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 for extmods_usage_list() function;
  • DESC - full description for extmod_print_desc() function.

Global variables

extmods

struct extmod extmods[];

Array of declared with EXTMOD_DECL extmod structures of size extmods_num.

extmods_num

int extmods_num;

Numerber of declared with EXTMOD_DECL extmod structures.

extmod

struct extmod *extmod;

Currently executing module. Valid only inside of extmod_exec() call. Outside it is NULL.

extmodname

char extmodname[];

Name of currently executing module.

Has correct value only inside of extmod_exec() call. Outside it is NULL.

Module name is:

  1. module name, if application was executed busybox-style (look extmod_extract description),
  2. composed as "<app_name>-<module_name>" otherwise.