2 ms·
Here's a POSIX compliant portable getopt() routine I wrote which uses this style. Is this hard to read? Note that it's several times shorter than every other im
by wahern 8y ago
Here's a POSIX compliant portable getopt() routine I wrote which uses this style. Is this hard to read? Note that it's several times shorter than every other implementation I've ever seen, and if I do say so myself I think it's eminently readable.
static int
u_getopt_r(int argc, char *const argv[], const char *shortopts, struct u_getopt_r *K)
{
K->optarg = NULL;
K->optopt = 0;
GETOPT_ENTER;
while (K->optind < argc) {
K->cp = argv[K->optind];
if (!K->cp || *(K->cp) != '-' || !strcmp(K->cp, "-")) {
break;
} else if (!strcmp(K->cp, "--")) {
K->optind++;
break;
}
for (;;) {
char *shortopt;
if (!(K->optopt = *++K->cp)) {
K->optind++;
break;
} else if (!(shortopt = strchr(shortopts, K->optopt))) {
getopt_err(argc, argv, shortopts, K, "illegal option -- %c\n", K->optopt);
GETOPT_YIELD('?');
} else if (shortopt[1] != ':') {
GETOPT_YIELD(K->optopt);
} else if (K->cp[1]) {
K->optarg = &K->cp[1];
K->optind++;
GETOPT_YIELD(K->optopt);
break;
} else if (K->optind + 1 < argc) {
K->optarg = argv[K->optind + 1];
K->optind += 2;
GETOPT_YIELD(K->optopt);
break;
} else {
getopt_err(argc, argv, shortopts, K, "option requires an argument -- %c\n", K->optopt);
K->optind++;
GETOPT_YIELD((*shortopts == ':')? ':' : '?');
break;
}
}
}
GETOPT_LEAVE;
return -1;
}
Here's macro magic, the complexity of which is more than made up for by the readability of the core code:
#define GETOPT_ENTER \
do { \
static const int pc0 = __LINE__; \
switch (pc0 + K->pc) { \
case __LINE__: (void)0
#define GETOPT_SAVE_AND_DO(do_statement) \
do { \
K->pc = __LINE__ - pc0; \
do_statement; \
case __LINE__: (void)0; \
} while (0)
#define GETOPT_YIELD(rv) \
GETOPT_SAVE_AND_DO(return (rv))
#define GETOPT_LEAVE \
GETOPT_SAVE_AND_DO(break); \
} \
} while (0)