Last active
October 5, 2020 01:06
-
-
Save Artoria2e5/aa706d9b5801739c30c7ef15cc3a5927 to your computer and use it in GitHub Desktop.
getopt(3) in the Solaris way, as a wrapper around getopt_long(3)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* sun_getopt - Solaris-style getopt(3), as a wrapper around getopt_long(3). | |
* | |
* Written by Mingye Wang (Artoria2e5). Dedicated to the public domain under | |
* Creative Commons Zero. | |
* | |
* Untested. Like not even fed to a compiler once. | |
*/ | |
#include "sun_getopt.h" | |
#include <getopt.h> | |
#include <stddef.h> | |
#include <stdlib.h> | |
struct sun_longopts_s { | |
const char *sun; | |
char *posix; | |
struct option *opts; | |
}; | |
#if __STDC_VERSION__ >= 201112L | |
static _Thread_local sun_longopts_t store = {NULL, NULL, NULL}; | |
#else | |
static sun_longopts_t store = {NULL, NULL, NULL}; | |
#endif | |
static int sun_getopt_compile(const char *__restrict from, sun_longopts_t *__restrict to) { | |
size_t len = strlen(from); | |
size_t opt_count = 0; | |
to->sun = from; | |
to->posix = malloc(len + 1); | |
if (!to->posix) return 0; | |
size_t opt_size = 16; | |
to->opts = malloc(opt_size * sizeof(struct option)); | |
if (!to->opts) return 0; | |
int optchar = '\0'; | |
char *to_str = to->posix; | |
const char* paren_start = NULL; | |
size_t colons = 0; | |
for (size_t i = 0; i < len; i++) { | |
if (!paren_start) { | |
if (from[i] == '(') { | |
in_paren = 1; | |
paren_start = &from[i]; | |
continue; | |
} | |
if (from[i] != ':') { | |
colons = 0; | |
optchar = from[i]; | |
} else { | |
colons++; | |
} | |
// Maybe we should filter out unprintable optchars? So they can be used as indices but not short args. | |
*to_str++ = from[i]; | |
} else if (from[i] == ')') { | |
if (++opt_count >= opt_size - 1) | |
if (!(to->opts = realloc(to->opts, | |
(opt_size *= 2) * sizeof(struct option)))) | |
return 0; | |
to->opts[opt_count] = { | |
strndup(paren_start + 1, &from[i] - paren_startn - 1), | |
colons > 1 ? optional_argument : colon == 1 ? required_argument : no_argument, | |
NULL, | |
optchar | |
}; | |
paren_start = NULL; | |
colons = 0; | |
optchar = '\0'; | |
} | |
} | |
*to_str = '\0'; | |
to->opts[++opt_count] = {NULL, 0, NULL, 0}; | |
return !paren_start; | |
} | |
int sun_getopt(int argc, char *const argv[], const char *optstring) { | |
if (!store.posix || strcmp(store.sun, optstring)) { | |
int status = sun_getopt_compile(optstring, &store); | |
if (!status) | |
return EOF; // FIXME | |
} | |
return getopt_long(argc, argv, store.posix, store.opts, NULL); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* sun_getopt - Solaris-style getopt(3), as a wrapper around getopt_long(3). | |
* | |
* Written by Mingye Wang (Artoria2e5). Dedicated to the public domain under | |
* Creative Commons Zero. | |
*/ | |
#ifndef SUN_GETOPT_H | |
#define SUN_GETOPT_H | |
extern char *optarg; | |
extern int optind; | |
extern int optopt; | |
extern int opterr; | |
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) | |
extern int optreset; | |
#endif | |
typedef struct sun_longopts_s sun_longopts_t; | |
int sun_getopt(int argc, char *const argv[], const char *optstring); | |
void sun_getopt_finish() | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment