diff options
| author | Oskari Timperi <oskari.timperi@iki.fi> | 2017-02-12 17:12:52 +0200 |
|---|---|---|
| committer | Oskari Timperi <oskari.timperi@iki.fi> | 2017-02-12 17:12:52 +0200 |
| commit | cd2faf64b2e995dee42e7e3911325d372c6604a1 (patch) | |
| tree | e0ab608cdd7005e759b570a5a4ec2031191bafb5 /tools/getopt.h | |
| parent | 54f78d73ec378fe1d62a696edeb2ddc5a59e2669 (diff) | |
| download | mqtt-cd2faf64b2e995dee42e7e3911325d372c6604a1.tar.gz mqtt-cd2faf64b2e995dee42e7e3911325d372c6604a1.zip | |
Add all the stuff
Diffstat (limited to 'tools/getopt.h')
| -rw-r--r-- | tools/getopt.h | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/tools/getopt.h b/tools/getopt.h new file mode 100644 index 0000000..5ed3145 --- /dev/null +++ b/tools/getopt.h @@ -0,0 +1,175 @@ +#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_ */ |
