Repository URL to install this package:
|
Version:
0.8.27 ▾
|
#ifndef _GETOPT_H_
#define _GETOPT_H_
#include <setjmp.h>
#include <stddef.h>
/**
* This getopt implementation parses options of the following forms:
* -a -b -c foo (single-character options)
* -abc foo (packed single-character options)
* -abcfoo (packed single-character options and an argument)
* --foo bar (long option)
* --foo=bar (long option and argument separated by '=')
*
* It does not support abbreviated options (e.g., interpreting --foo as
* --foobar when there are no other --foo* options) since that misfeature
* results in breakage when new options are added. It also does not support
* options appearing after non-options (e.g., "cp foo bar -R") since that is
* a horrible GNU perversion.
*/
/* Work around LLVM bug. */
#ifdef __clang__
#warning Working around bug in LLVM optimizer
#warning For more details see https://llvm.org/bugs/show_bug.cgi?id=27190
#define DO_SETJMP _DO_SETJMP(__LINE__)
#define _DO_SETJMP(x) __DO_SETJMP(x)
#define __DO_SETJMP(x) \
void * getopt_initloop = && getopt_initloop_ ## x; \
getopt_initloop_ ## x:
#define DO_LONGJMP \
goto *getopt_initloop
#else
#define DO_SETJMP \
sigjmp_buf getopt_initloop; \
if (!getopt_initialized) \
sigsetjmp(getopt_initloop, 0)
#define DO_LONGJMP \
siglongjmp(getopt_initloop, 1)
#endif
/* Avoid namespace collisions with libc getopt. */
#define getopt libcperciva_getopt
#define optarg libcperciva_optarg
#define optind libcperciva_optind
#define opterr libcperciva_opterr
#define optreset libcperciva_optreset
/* Standard getopt global variables. */
extern const char * optarg;
extern int optind, opterr, optreset;
/* Dummy option string, equal to "(dummy)". */
#define GETOPT_DUMMY getopt_dummy
/**
* GETOPT(argc, argv):
* When called for the first time (or the first time after optreset is set to
* a nonzero value), return GETOPT_DUMMY, aka. "(dummy)". Thereafter, return
* the next option string and set optarg / optind appropriately; abort if not
* properly initialized when not being called for the first time.
*/
#define GETOPT(argc, argv) getopt(argc, argv)
/**
* GETOPT_SWITCH(ch):
* Jump to the appropriate GETOPT_OPT, GETOPT_OPTARG, GETOPT_MISSING_ARG, or
* GETOPT_DEFAULT based on the option string ${ch}. When called for the first
* time, perform magic to index the options.
*
* GETOPT_SWITCH(ch) is equivalent to "switch (ch)" in a standard getopt loop.
*/
#define GETOPT_SWITCH(ch) \
volatile size_t getopt_ln_min = __LINE__; \
volatile size_t getopt_ln = getopt_ln_min - 1; \
volatile int getopt_default_missing = 0; \
DO_SETJMP; \
switch (getopt_initialized ? getopt_lookup(ch) + getopt_ln_min : getopt_ln++)
/**
* GETOPT_OPT(os):
* Jump to this point when the option string ${os} is passed to GETOPT_SWITCH.
*
* GETOPT_OPT("-x") is equivalent to "case 'x'" in a standard getopt loop
* which has an optstring containing "x".
*/
#define GETOPT_OPT(os) _GETOPT_OPT(os, __LINE__)
#define _GETOPT_OPT(os, ln) __GETOPT_OPT(os, ln)
#define __GETOPT_OPT(os, ln) \
case ln: \
if (getopt_initialized) \
goto getopt_skip_ ## ln; \
getopt_register_opt(os, ln - getopt_ln_min, 0); \
DO_LONGJMP; \
getopt_skip_ ## ln
/**
* GETOPT_OPTARG(os):
* Jump to this point when the option string ${os} is passed to GETOPT_SWITCH,
* unless no argument is available, in which case jump to GETOPT_MISSING_ARG
* (if present) or GETOPT_DEFAULT (if not).
*
* GETOPT_OPTARG("-x") is equivalent to "case 'x'" in a standard getopt loop
* which has an optstring containing "x:".
*/
#define GETOPT_OPTARG(os) _GETOPT_OPTARG(os, __LINE__)
#define _GETOPT_OPTARG(os, ln) __GETOPT_OPTARG(os, ln)
#define __GETOPT_OPTARG(os, ln) \
case ln: \
if (getopt_initialized) \
goto getopt_skip_ ## ln; \
getopt_register_opt(os, ln - getopt_ln_min, 1); \
DO_LONGJMP; \
getopt_skip_ ## ln
/**
* GETOPT_MISSING_ARG:
* Jump to this point if an option string specified in GETOPT_OPTARG is seen
* but no argument is available.
*
* GETOPT_MISSING_ARG is equivalent to "case ':'" in a standard getopt loop
* which has an optstring starting with ":". As such, it also has the effect
* of disabling warnings about invalid options, as if opterr had been zeroed.
*/
#define GETOPT_MISSING_ARG _GETOPT_MISSING_ARG(__LINE__)
#define _GETOPT_MISSING_ARG(ln) __GETOPT_MISSING_ARG(ln)
#define __GETOPT_MISSING_ARG(ln) \
case ln: \
if (getopt_initialized) \
goto getopt_skip_ ## ln; \
getopt_register_missing(ln - getopt_ln_min); \
DO_LONGJMP; \
getopt_skip_ ## ln
/**
* GETOPT_DEFAULT:
* Jump to this point if an unrecognized option is seen or if an option
* specified in GETOPT_OPTARG is seen, no argument is available, and there is
* no GETOPT_MISSING_ARG label.
*
* GETOPT_DEFAULT is equivalent to "case '?'" in a standard getopt loop.
*
* NOTE: This MUST be present in the GETOPT_SWITCH statement, and MUST occur
* after all other GETOPT_* labels.
*/
#define GETOPT_DEFAULT _GETOPT_DEFAULT(__LINE__)
#define _GETOPT_DEFAULT(ln) __GETOPT_DEFAULT(ln)
#define __GETOPT_DEFAULT(ln) \
goto getopt_skip_ ## ln; \
case ln: \
getopt_initialized = 1; \
break; \
default: \
if (getopt_initialized) \
goto getopt_skip_ ## ln; \
if (!getopt_default_missing) { \
getopt_setrange(ln - getopt_ln_min); \
getopt_default_missing = 1; \
} \
DO_LONGJMP; \
getopt_skip_ ## ln
/*
* The back-end implementation. These should be considered internal
* interfaces and not used directly.
*/
const char * getopt(int, char * const []);
size_t getopt_lookup(const char *);
void getopt_register_opt(const char *, size_t, int);
void getopt_register_missing(size_t);
void getopt_setrange(size_t);
extern const char * getopt_dummy;
extern int getopt_initialized;
#endif /* !_GETOPT_H_ */