1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 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_ */
|