libslack(prog) - program framework module
#include <slack/prog.h>
void prog_init(void); const char *prog_set_name(const char *name); Options *prog_set_options(Options *options); const char *prog_set_syntax(const char *syntax); const char *prog_set_desc(const char *desc); const char *prog_set_version(const char *version); const char *prog_set_date(const char *date); const char *prog_set_author(const char *author); const char *prog_set_contact(const char *contact); const char *prog_set_vendor(const char *vendor); const char *prog_set_url(const char *url); const char *prog_set_legal(const char *legal); Msg *prog_set_out(Msg *out); Msg *prog_set_err(Msg *err); Msg *prog_set_dbg(Msg *dbg); size_t prog_set_debug_level(size_t debug_level); size_t prog_set_verbosity_level(size_t verbosity_level); int prog_set_locker(Locker *locker); const char *prog_name(void); const Options *prog_options(void); const char *prog_syntax(void); const char *prog_desc(void); const char *prog_version(void); const char *prog_date(void); const char *prog_author(void); const char *prog_contact(void); const char *prog_vendor(void); const char *prog_url(void); const char *prog_legal(void); Msg *prog_out(void); Msg *prog_err(void); Msg *prog_dbg(void); size_t prog_debug_level(void); size_t prog_verbosity_level(void); int prog_out_fd(int fd); int prog_out_stdout(void); int prog_out_file(const char *path); int prog_out_syslog(const char *ident, int option, int facility); int prog_out_none(void); int prog_err_fd(int fd); int prog_err_stderr(void); int prog_err_file(const char *path); int prog_err_syslog(const char *ident, int option, int facility); int prog_err_none(void); int prog_dbg_fd(int fd); int prog_dbg_stdout(void); int prog_dbg_stderr(void); int prog_dbg_file(const char *path); int prog_dbg_syslog(const char *id, int option, int facility); int prog_dbg_none(void); int prog_opt_process(int ac, char **av); void prog_usage_msg(const char *fmt, ...); void prog_help_msg(void); void prog_version_msg(void); const char *prog_basename(const char *path); extern Options prog_options_table[1];
typedef struct option option; typedef struct Option Option; typedef struct Options Options;
typedef void (*opt_action_int_t)(int); typedef void (*opt_action_optional_int_t)(int *); typedef void (*opt_action_string_t)(const char *); typedef void (*opt_action_optional_string_t)(const char *); typedef void (*opt_action_none_t)(void);
enum OptionArgument { OPT_NONE, OPT_INTEGER, OPT_STRING };
enum OptionAction { OPT_NOTHING, OPT_VARIABLE, OPT_FUNCTION };
typedef enum OptionArgument OptionArgument; typedef enum OptionAction OptionAction;
struct Option { const char *name; char short_name; const char *argname; const char *desc; int has_arg; OptionArgument arg_type; OptionAction action; void *object; };
struct Options { Options *parent; Option *options; };
int opt_process(int argc, char **argv, Options *options); char *opt_usage(char *buf, size_t size, Options *options);
This module provides functions for arbitrary programs. The services include program identification; flexible, complete command line option processing; help, usage and version messages; flexible debug, verbose, error and normal messaging (simple call syntax with arbitrary message destinations including multiplexing).
This module exposes an alternate interface to GNU getopt_long(3). It defines a way to specify command line option syntax, semantics and descriptions in multiple, discrete chunks. The getopt functions require that the client specify the syntax and partial semantics for all options in the same place (if it is to be done statically). This can be annoying when library modules require their own command line options. This module allows various parts of a program to (statically) specify their own command line options independently and link them together via parent pointers.
Option syntax is specified in much the same way as for GNU
getopt_long(3). Option semantics are specified by an action (OPT_NOTHING
, OPT_VARIABLE
or OPT_FUNCTION
), an argument type (OPT_NONE
, OPT_INTEGER
or OPT_STRING
) and an object (int *
,
char **
, func()
, func(int)
or func(char *)
).
The opt_process() and opt_usage() functions are used by the prog functions and needn't be used directly. Instead, use prog_opt_process(3) to execute options and prog_usage_msg(3) and prog_help_msg() to construct usage and help message directly from the supplied option data. They are exposed in case you don't want to use any other part of this module.
void prog_init(void)
Initialises the message, error and debug destinations to stdout
,
stderr
and stderr
, respectively. This function must be called before any other functions in
this module or the err module.
const char *prog_set_name(const char *name)
Sets the program's name to name
. This is used when composing usage, help, version and error messages.
Returns name
.
Options *prog_set_options(Options *options)
Sets the program's options to options
. This is used when processing the command line options with prog_opt_process(). Returns options
.
const char *prog_set_syntax(const char *syntax)
Sets the program's syntax description to syntax
. This is used when composing usage and help messages. It must contain a
description of the command line arguments, excluding any options. Returns syntax
.
const char *prog_set_desc(const char *desc)
Sets the program's description to desc
. This is used when composing help messages. Returns desc
.
const char *prog_set_version(const char *version)
Sets the program's version to version
. This is used when composing help and version messages. Returns version
.
const char *prog_set_date(const char *date)
Sets the program's release date to date
. This is used when composing help messages. Returns date
.
const char *prog_set_author(const char *author)
Sets the program's author to author
. This is used when composing help messages. It must contain the (free
format) name of the author. Returns
author
.
const char *prog_set_contact(const char *contact)
Sets the program's contact address to contact
. This is used when composing help messages. It must contain the email
address to which bug reports should be sent. Returns contact
.
const char *prog_set_vendor(const char *vendor)
Sets the program's vendor to vendor
. This is used when composing help messages. It must contain the (free
format) name of the vendor. Returns
vendor
.
const char *prog_set_url(const char *url)
Sets the program's URL to url
. This is used when composing help messages. It must contain the URL where
the program can be downloaded. Returns url
.
const char *prog_set_legal(const char *legal)
Sets the program's legal notice to legal
. This is used when composing help messages. It is assumed that the legal
notice may contain multiple lines and so must contain its own newline
characters. Returns legal
.
Msg *prog_set_out(Msg *out)
Sets the program's message destination to out
. This is used by msg()
and vmsg() which are, in turn, used to emit usage, version and help messages. The
program message destination is set to standard output by
prog_init() but it can be anything. However, it is probably best to leave it as
standard output until after command line option processing is complete. See msg() for details. Returns out
.
Msg *prog_set_err(Msg *err)
Sets the program's error message destination to err
. This is used by
error(3), errorsys(3), fatal(3), fatalsys(3), dump(3) and
dumpsys(3). The program error message destination is set to standard error by prog_init(3) but it can be anything. See msg(3) for details. Returns err
.
Msg *prog_set_dbg(Msg *dbg)
Sets the program's debug message destination to dbg
. This is set to standard error by prog_init(3) but it can be set to anything. See
msg(3) for details. Returns dbg
.
ssize_t prog_set_debug_level(size_t debug_level)
Sets the program's debug level to debug_level
. This is used when determining whether or not to emit a debug message.
Debug messages with a level that is lower than the program debug level are
emited. On success, returns the previous debug level. On error, returns -1
.
ssize_t prog_set_verbosity_level(size_t verbosity_level)
Sets the program's verbosity level to verbosity_level
. This is used to determine whether or not to emit verbose messages.
Verbose messages with a level that is lower than the program verbosity
level are emitted. On success, returns the previous verbosity level. On
error, returns -1
.
int prog_set_locker(Locker *locker)
Sets the locker (multiple thread synchronisation strategy) for this module.
This is only needed in multi-threaded programs. See thread(3)|thread(3)
for details. On success, returns 0
. On error, returns -1
.
const char *prog_name(void)
Returns the program's name.
const Options *prog_options(void)
Returns the program's options.
const char *prog_syntax(void)
Returns the program's syntax description.
const char *prog_desc(void)
Returns the program's description.
const char *prog_version(void)
Returns the program's version string.
const char *prog_date(void)
Returns the program's release date.
const char *prog_author(void)
Returns the program's author.
const char *prog_contact(void)
Returns the program's contact address.
const char *prog_vendor(void)
Returns the program's vendor.
const char *prog_url(void)
Returns the program's URL.
const char *prog_legal(void)
Returns the program's legal notice.
Msg *prog_out(void)
Returns the program's message destination.
Msg *prog_err(void)
Returns the program's error message destination.
Msg *prog_dbg(void)
Returns the program's debug message destination.
size_t prog_debug_level(void)
Returns the program's debug level.
size_t prog_verbosity_level(void)
Returns the program's verbosity level.
int prog_out_fd(int fd)
Sets the program's message destination to be the file descriptor specified
by fd
. On success, returns 0. On error, returns -1.
int prog_out_stdout(void)
Sets the program's message destination to be standard output. On success, returns 0. On error, returns -1.
int prog_out_file(const char *path)
Sets the program's message destination to be the file specified by path
. On success, returns 0. On error, returns -1.
int prog_out_syslog(const char *ident, int option, int facility)
Sets the program's message destination to be syslog initialised with
ident
, option
and facility
. On success, returns 0. On error, returns -1.
int prog_out_none(void)
Sets the program's message destination to NULL
. This disables all normal messages. Returns 0.
int prog_err_fd(int fd)
Sets the program's error message destination to be the file descriptor
specified by fd
. On success, returns 0. On error, returns -1.
int prog_err_stderr(void)
Sets the program's error message destination to be standard error. On success, returns 0. On error, returns -1.
int prog_err_file(const char *path)
Sets the program's error message destination to be the file specified by
path
. On success, returns 0. On error, returns -1.
int prog_err_syslog(const char *ident, int option, int facility)
Sets the program's error message destination to be syslog initialised with ident
, option
and facility
. On success, returns 0. On error, returns -1.
int prog_err_none(void)
Sets the program's error message destination to NULL
. This disables all error messages. Returns 0.
int prog_dbg_fd(int fd)
Sets the program's debug message destination to be the file descriptor
specified by fd
. On success, returns 0. On error, returns -1.
int prog_dbg_stdout(void)
Sets the program's debug message destination to be standard output. On success, returns 0. On error, returns -1.
int prog_dbg_stderr(void)
Sets the program's debug message destination to be standard error. On success, returns 0. On error, returns -1.
int prog_dbg_file(const char *path)
Sets the program's debug message destination to be the file specified by
path
. On success, returns 0. On error, returns -1.
int prog_dbg_syslog(const char *id, int option, int facility)
Sets the program's debug message destination to be syslog initialised with ident
, option
and facility
. On success, returns 0. On error, returns -1.
int prog_dbg_none(void)
Sets the program's debug message destination to NULL
. This disables all debug messages. Returns 0.
int prog_opt_process(int ac, const char **av)
Parses and processes the command line options in av
. If there is an error, a usage message is emitted and the program
terminates. This function is just an interface to GNU getopt_long(3) that provides easier, more flexible, and more complete option handling. As
well as supplying the syntax for options, this function requires their
semantics and descriptions. The descriptions allow usage and help messages
to be automatically composed by
prog_usage_msg(3) and prog_help_msg(3). The semantics (which may be either a variable assignment or a function
invocation) allow complete command line option processing to be performed
with a single call to this function. On success, returns optind
. On error (i.e. invalid option), calls prog_usage_msg() which terminates the program with a return code of -1. See below (opt_usage()) for details on specifying option data. On error (other), returns -1
.
void prog_usage_msg(const char *fmt, ...)
Emits a program usage error message then terminates the program with a
return code of 1. The usage message consists of the program's name, syntax,
options descriptions and the given message. fmt
is a printf-like format string. Any remaining arguments are processed as in printf(3).
Warning: Do not under any circumstances ever pass a non-literal string as the fmt argument unless you know exactly how many conversions will take place. Being careless with this is a very good way to build potential security holes into your programs. The same is true for all functions that take a printf()-like format string as an argument.
prog_usage_msg(buf); // EVIL prog_usage_msg("%s", buf); // GOOD
void prog_help_msg(void)
Emits a program help message then terminates the program with a return code of 0. This message consists of the program's usage message, description, name, version, release date, author, vendor, URL, legal notice and contact address.
void prog_version_msg(void)
Emits a program version message then terminates the program with a return code of 0. This message consists of the program's name and version.
const char *prog_basename(const char *path)
Returns the filename part of path
.
extern Options prog_options_table[1]
Contains the syntax, semantics and descriptions of some options that are available to all programs that use libslack. These options are:
help
Print a help message then exit
version
Print a version message then exit
verbose
[=level]Set the verbosity level (Defaults to 1 if level not supplied)
debug
[=level]Set the debug level (Defaults to 1 if level not supplied)
If your program supports no other options than these, prog_options_table
can be passed directly to prog_set_options(3). Otherwise,
prog_options_table should be assigned to the parent
field of the
Options
structure that will be passed to prog_set_options(3).
int opt_process(int argc, char **argv, Options *options)
Parses argv
for options specified in options
. Uses GNU
getopt_long(3). As each option is encountered, its corresponding action is performed. On
success, returns optind
. On error (i.e. invalid option), returns -1.
The following table shows the actions that are applied to an option's
object
based on its has_arg
, arg_type
and arg_action
attributes and whether or not an argument is present.
has_arg arg_type arg_action optarg action ~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~ ~~~~~~ required_argument OPT_INTEGER OPT_VARIABLE yes *object = atoi(argument) required_argument OPT_STRING OPT_VARIABLE yes *object = argument required_argument OPT_INTEGER OPT_FUNCTION yes object(atoi(argument)) required_argument OPT_STRING OPT_FUNCTION yes object(argument)
optional_argument OPT_INTEGER OPT_VARIABLE yes *object = atoi(argument) optional_argument OPT_STRING OPT_VARIABLE yes *object = argument optional_argument OPT_INTEGER OPT_FUNCTION yes object(&atoi(argument)) optional_argument OPT_STRING OPT_FUNCTION yes object(argument)
optional_argument OPT_INTEGER OPT_VARIABLE no ++*object optional_argument OPT_STRING OPT_VARIABLE no nothing optional_argument OPT_INTEGER OPT_FUNCTION no object(NULL) optional_argument OPT_STRING OPT_FUNCTION no object(NULL)
no_argument OPT_NONE OPT_VARIABLE no ++*object no_argument OPT_NONE OPT_FUNCTION no object()
char *opt_usage(char *buf, size_t size, Options *options)
Writes a usage message into buf
that displays the names, syntax and descriptions of all options in options
. options
is traversed depth first so the chunk with the NULL
parent appears first. Each chunk of options is preceeded by a blank line. No more
than size
bytes are written, including the terminating nul
character. The string returned will look like:
-a, --aaa -- no-arg/var option -b, --bbb -- no-arg/func option -c, --ccc=arg -- int-arg/var option -d, --ddd=arg -- int-arg/func option -e, --eee=arg -- str-arg/var option -f, --fff=arg -- str-arg/func option -g, --ggg[=arg] -- opt-int-arg/var option -h, --hhh[=arg] -- opt-str-arg/func option with one of those really, really, really, long descriptions that goes on and on and even contains a really long url: http://www.zip.com.au/~joe/fairly/long/url/index.html would you believe? Here it is again! http://www.zip.com.au/~joe/fairly/long/url/index.html#just_kidding
MT-Disciplined - prog functions
By default, this module is not thread safe because most programs are single threaded and synchronisation doesn't come for free. For multi threaded programs, use prog_set_locker() to synchronise access to this module's data before creating the threads that will access it.
Unsafe - opt functions
opt_process() and opt_usage() must only be used in the main thread. They should not be needed anywhere else.
The following program:
#include <stdio.h> #include <slack/prog.h>
char *name = NULL; int minimum = 0; int reverse = 0;
void setup_syslog(char *facility) { ... } void parse_config(char *path) { ... }
Option example_optab[] = { { "name", 'n', "name", "Provide a name", required_argument, OPT_STRING, OPT_VARIABLE, &name }, { "minimum", 'm', "minval", "Ignore everything below minimum", required_argument, OPT_INTEGER, OPT_VARIABLE, &minimum }, { "syslog", 's', "facility.priority", "Send client's output to syslog (defaults to local0.debug)", optional_argument, OPT_STRING, OPT_FUNCTION, (void *)setup_syslog }, { "reverse", 'r', NULL, "Reverse direction", no_argument, OPT_NONE, OPT_VARIABLE, &reverse }, { "config", 'c', "path", "Specify the configuration file", required_argument, OPT_STRING, OPT_FUNCTION, (void *)parse_config }, { NULL, '\0', NULL, NULL, 0, 0, 0, NULL } };
Options options[1] = {{ prog_options_table, example_optab }};
int main(int ac, char **av) { int a; prog_init(); prog_set_name("example"); prog_set_syntax("[options] arg..."); prog_set_options(options); prog_set_version("1.0"); prog_set_date("20010215"); prog_set_author("raf <raf@raf.org>"); prog_set_contact(prog_author()); prog_set_url("http://libslack.org/"); prog_set_legal("This software is released under the terms of the GPL.\n"); prog_set_desc("This program is an example of the prog module.\n");
for (a = prog_opt_process(ac, av); a < ac; ++a) msg("av[%d] = \"%s\"\n", a, av[a]);
return 0; }
will behave like:
$ example --version # to stdout example-1.0
$ example --help # to stdout usage: example [options] arg... options:
-h, --help - Print a help message then exit -V, --version - Print a version message then exit -v, --verbose[=level] - Set the verbosity level -d, --debug[=level] - Set the debug level
-n, --name=name - Provide a name -m, --minimum=minval - Ignore everything below minimum -s, --syslog[=facility.priority] - Send client's output to syslog (defaults to local0.debug) -r, --reverse - Reverse direction -c, --config=path - Specify the configuration file
This program is an example of the prog module.
Name: example Version: 1.0 Date: 20010215 Author: raf <raf@raf.org> URL: http://libslack.org/
This software is released under the terms of the GPL.
Report bugs to raf <raf@raf.org>
$ example -x # to stderr ./example: invalid option -- x usage: example [options] arg... options: -h, --help - Print a help message then exit -V, --version - Print a version message then exit -v, --verbose[=level] - Set the verbosity level -d, --debug[=level] - Set the debug level -n, --name=name - Provide a name -m, --minimum=minval - Ignore everything below minimum -s, --syslog[=facility.priority] - Send client's output to syslog (defaults to local0.debug) -r, --reverse - Reverse direction -c, --config=path - Specify the configuration file
$ example a b c # to stdout av[1] = "a" av[2] = "b" av[3] = "c"
libslack(3), getopt_long(3), err(3), msg(3), opt(3), prop(3), sig(3), thread(3)
20010215 raf <raf@raf.org>