aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--make.c2
-rw-r--r--src/codegen.c26
-rw-r--r--src/main.c51
-rw-r--r--vendor/optparse-master/.gitignore4
-rw-r--r--vendor/optparse-master/Makefile10
-rw-r--r--vendor/optparse-master/README.md241
-rw-r--r--vendor/optparse-master/UNLICENSE24
-rw-r--r--vendor/optparse-master/examples/Makefile18
-rw-r--r--vendor/optparse-master/examples/long.c56
-rw-r--r--vendor/optparse-master/examples/short.c47
-rw-r--r--vendor/optparse-master/examples/subcommands.c120
-rw-r--r--vendor/optparse-master/optparse.h409
-rw-r--r--vendor/optparse-master/test.c302
13 files changed, 1302 insertions, 8 deletions
diff --git a/make.c b/make.c
index 5566859..be85ecf 100644
--- a/make.c
+++ b/make.c
@@ -12,6 +12,7 @@
#define TARGET "oryx"
#define GMPDIR "vendor/gmp-6.3.0"
+#define OPDIR "vendor/optparse-master"
enum {
SIMD_AVX2 = 1 << 0,
@@ -21,6 +22,7 @@ enum {
static char *cflags_all[] = {
("-I" GMPDIR),
+ ("-I" OPDIR),
"-pipe",
"-std=c11",
"-Wall",
diff --git a/src/codegen.c b/src/codegen.c
index 1567adf..a9b1430 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -29,7 +29,6 @@
LLVMInitialize##x##TargetMC(); \
} while (false)
-
/* A context structure we can pass to all the codegen functions just so they
have easy access to everything */
struct cgctx {
@@ -53,9 +52,11 @@ struct cgctx {
strview_t namespace;
};
+static void codegenast(struct cgctx);
static LLVMTypeRef type2llvm(struct cgctx, type_t);
-static void codegenast(struct cgctx);
+extern bool lflag, sflag;
+extern const char *oflag;
void
codegen(const char *file, mpq_t *folds, scope_t *scps, type_t *types, ast_t ast,
@@ -103,7 +104,26 @@ codegen(const char *file, mpq_t *folds, scope_t *scps, type_t *types, ast_t ast,
if (LLVMVerifyModule(ctx.mod, LLVMReturnStatusAction, &error) == 1)
err("codegen: %s", error);
- LLVMDumpModule(ctx.mod);
+ if (lflag) {
+ if (oflag == NULL)
+ LLVMDumpModule(ctx.mod);
+ else if (LLVMPrintModuleToFile(llmod, oflag, &error) == 1)
+ err("codegen: %s", error);
+ } else {
+ LLVMCodeGenFileType ft;
+ const char *dst = oflag == NULL ? "out.o" : oflag;
+
+ if (sflag) {
+ size_t n = strlen(dst);
+ char *buf = memcpy(tmpalloc(ctx.s, n + 1, 1), dst, n);
+ buf[n - 1] = 's';
+ buf[n - 0] = 0;
+ dst = buf;
+ ft = LLVMAssemblyFile;
+ } else
+ ft = LLVMObjectFile;
+ LLVMTargetMachineEmitToFile(llmach, llmod, dst, ft, &error);
+ }
#if DEBUG
tmpfree(ctx.s);
diff --git a/src/main.c b/src/main.c
index a8dabea..cc6cfd7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -6,6 +6,9 @@
#include <unistd.h>
#include <gmp.h>
+#define OPTPARSE_API static
+#define OPTPARSE_IMPLEMENTATION
+#include <optparse.h>
#include "alloc.h"
#include "analyzer.h"
@@ -20,16 +23,54 @@
static char *readfile(const char *file, size_t *bufsz)
__attribute__((returns_nonnull, nonnull));
+bool lflag, sflag;
+const char *oflag;
+
int
main(int argc, char **argv)
{
- if (argc != 2) {
- fputs("Usage: oryx file\n", stderr);
- exit(EXIT_FAILURE);
+ struct optparse_long longopts[] = {
+ {"assembly", 's', OPTPARSE_NONE},
+ {"emit-llvm", 'l', OPTPARSE_NONE},
+ {"output", 'o', OPTPARSE_REQUIRED},
+ {0},
+ };
+
+ int opt;
+ struct optparse opts;
+ optparse_init(&opts, argv);
+
+ while ((opt = optparse_long(&opts, longopts, NULL)) != -1) {
+ switch (opt) {
+ case 'o':
+ oflag = opts.optarg;
+ break;
+ case 'l':
+ lflag = true;
+ break;
+ case 's':
+ sflag = true;
+ break;
+ default:
+ /* TODO: Add warn() to errors.h */
+ fprintf(stderr, "oryx: %s\n", opts.errmsg);
+usage:
+ fprintf(stderr, "Usage: oryx [-l | -s] [-o file] source\n");
+ exit(EXIT_FAILURE);
+ }
}
+ if (lflag && sflag)
+ goto usage;
+
+ argc -= opts.optind;
+ argv += opts.optind;
+
+ if (argc != 1)
+ goto usage;
+
size_t srclen;
- char *src = readfile(argv[1], &srclen);
+ char *src = readfile(argv[0], &srclen);
aux_t aux;
mpq_t *folds;
@@ -40,7 +81,7 @@ main(int argc, char **argv)
lexemes_t toks = lexstring(src, srclen);
ast_t ast = parsetoks(toks, &aux);
analyzeprog(ast, aux, toks, &a, &types, &scps, &folds);
- codegen(argv[1], folds, scps, types, ast, aux, toks);
+ codegen(argv[0], folds, scps, types, ast, aux, toks);
#if DEBUG
for (size_t i = 0; i < ast.len; i++) {
diff --git a/vendor/optparse-master/.gitignore b/vendor/optparse-master/.gitignore
new file mode 100644
index 0000000..59c5841
--- /dev/null
+++ b/vendor/optparse-master/.gitignore
@@ -0,0 +1,4 @@
+test
+examples/long
+examples/short
+examples/subcommands
diff --git a/vendor/optparse-master/Makefile b/vendor/optparse-master/Makefile
new file mode 100644
index 0000000..392b4eb
--- /dev/null
+++ b/vendor/optparse-master/Makefile
@@ -0,0 +1,10 @@
+CFLAGS = -ansi -pedantic -Wall -Wextra -g3
+
+test : test.c optparse.h
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ test.c $(LDLIBS)
+
+run : test
+ ./test -abdfoo -c bar subcommand example.txt -a
+
+clean :
+ rm -f test
diff --git a/vendor/optparse-master/README.md b/vendor/optparse-master/README.md
new file mode 100644
index 0000000..2a85d56
--- /dev/null
+++ b/vendor/optparse-master/README.md
@@ -0,0 +1,241 @@
+# Optparse
+
+Optparse is a public domain, portable, reentrant, embeddable, getopt-like
+option parser. As a single header file, it's trivially dropped into any
+project. It supports POSIX getopt option strings, GNU-style long options,
+argument permutation, and subcommand processing.
+
+To get the implementation, define `OPTPARSE_IMPLEMENTATION` before
+including `optparse.h`.
+
+~~~c
+#define OPTPARSE_IMPLEMENTATION
+#include "optparse.h"
+~~~
+
+Optionally define `OPTPARSE_API` to control the API's visibility
+and/or linkage (`static`, `__attribute__`, `__declspec`).
+
+~~~c
+#define OPTPARSE_API static
+#include "optparse.h"
+~~~
+
+## Why not getopt()?
+
+The POSIX getopt option parser has three fatal flaws. These flaws are
+solved by Optparse.
+
+1. The getopt parser state is stored entirely in global variables,
+some of which are static and inaccessible. This means only one thread
+can use getopt. It also means it's not possible to recursively parse
+nested sub-arguments while in the middle of argument parsing. Optparse
+fixes this by storing all state on a local struct.
+
+2. The POSIX standard provides no way to properly reset the parser.
+For portable code this means getopt is only good for one run, over one
+argv with one option string. It also means subcommand options cannot
+be reliably processed with getopt. Most implementations provide an
+implementation-specific method to reset the parser, but this is not
+portable. Optparse provides an `optparse_arg()` function for stepping
+through non-option arguments, and parsing of options can continue
+again at any time with a different option string. The Optparse struct
+itself could be passed around to subcommand handlers for additional
+subcommand option parsing. If a full parser reset is needed,
+`optparse_init()` can be called again.
+
+3. In getopt, error messages are printed to stderr. This can be
+disabled with opterr, but the messages themselves are still
+inaccessible. Optparse solves this by writing the error message to its
+errmsg field, which can be printed to anywhere. The downside to
+Optparse is that this error message will always be in English rather
+than the current locale.
+
+## Permutation
+
+By default, argv is permuted as it is parsed, moving non-option
+arguments to the end of the array. This can be disabled by setting the
+`permute` field to 0 after initialization.
+
+~~~c
+struct optparse options;
+optparse_init(&options, argv);
+options.permute = 0;
+~~~
+
+## Drop-in Replacement
+
+Optparse's interface should be familiar with anyone accustomed to
+getopt. It's nearly a drop-in replacement. The option string has the
+same format and the parser struct fields have the same names as the
+getopt global variables (optarg, optind, optopt).
+
+The long option parser `optparse_long()` API is very similar to GNU's
+`getopt_long()` and can serve as a portable, embedded replacement.
+
+Optparse does not allocate memory. Furthermore, Optparse has no
+dependencies, including libc itself, so it can be used in situations
+where the standard C library cannot.
+
+See `optparse.h` for full API documentation.
+
+## Example Usage
+
+Here's a traditional getopt setup.
+
+~~~c
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <getopt.h>
+
+int main(int argc, char **argv)
+{
+ bool amend = false;
+ bool brief = false;
+ const char *color = "white";
+ int delay = 0;
+
+ int option;
+ while ((option = getopt(argc, argv, "abc:d::")) != -1) {
+ switch (option) {
+ case 'a':
+ amend = true;
+ break;
+ case 'b':
+ brief = true;
+ break;
+ case 'c':
+ color = optarg;
+ break;
+ case 'd':
+ delay = optarg ? atoi(optarg) : 1;
+ break;
+ case '?':
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Print remaining arguments. */
+ for (; optind < argc; optind++)
+ printf("%s\n", argv[optind]);
+ return 0;
+}
+~~~
+
+Here's the same thing translated to Optparse.
+
+~~~c
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define OPTPARSE_IMPLEMENTATION
+#define OPTPARSE_API static
+#include "optparse.h"
+
+int main(int argc, char **argv)
+{
+ bool amend = false;
+ bool brief = false;
+ const char *color = "white";
+ int delay = 0;
+
+ char *arg;
+ int option;
+ struct optparse options;
+
+ optparse_init(&options, argv);
+ while ((option = optparse(&options, "abc:d::")) != -1) {
+ switch (option) {
+ case 'a':
+ amend = true;
+ break;
+ case 'b':
+ brief = true;
+ break;
+ case 'c':
+ color = options.optarg;
+ break;
+ case 'd':
+ delay = options.optarg ? atoi(options.optarg) : 1;
+ break;
+ case '?':
+ fprintf(stderr, "%s: %s\n", argv[0], options.errmsg);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Print remaining arguments. */
+ while ((arg = optparse_arg(&options)))
+ printf("%s\n", arg);
+ return 0;
+}
+~~~
+
+And here's a conversion to long options.
+
+~~~c
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define OPTPARSE_IMPLEMENTATION
+#define OPTPARSE_API static
+#include "optparse.h"
+
+int main(int argc, char **argv)
+{
+ struct optparse_long longopts[] = {
+ {"amend", 'a', OPTPARSE_NONE},
+ {"brief", 'b', OPTPARSE_NONE},
+ {"color", 'c', OPTPARSE_REQUIRED},
+ {"delay", 'd', OPTPARSE_OPTIONAL},
+ {0}
+ };
+
+ bool amend = false;
+ bool brief = false;
+ const char *color = "white";
+ int delay = 0;
+
+ char *arg;
+ int option;
+ struct optparse options;
+
+ optparse_init(&options, argv);
+ while ((option = optparse_long(&options, longopts, NULL)) != -1) {
+ switch (option) {
+ case 'a':
+ amend = true;
+ break;
+ case 'b':
+ brief = true;
+ break;
+ case 'c':
+ color = options.optarg;
+ break;
+ case 'd':
+ delay = options.optarg ? atoi(options.optarg) : 1;
+ break;
+ case '?':
+ fprintf(stderr, "%s: %s\n", argv[0], options.errmsg);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Print remaining arguments. */
+ while ((arg = optparse_arg(&options)))
+ printf("%s\n", arg);
+
+ return 0;
+}
+~~~
+
+## Subcommand Parsing
+
+To parse subcommands, first parse options with permutation disabled. These
+are the "global" options that come before the subcommand. Then parse the
+remainder, optionally permuting, as a new option array.
+
+See `examples/subcommands.c` for a complete, working example.
diff --git a/vendor/optparse-master/UNLICENSE b/vendor/optparse-master/UNLICENSE
new file mode 100644
index 0000000..68a49da
--- /dev/null
+++ b/vendor/optparse-master/UNLICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
diff --git a/vendor/optparse-master/examples/Makefile b/vendor/optparse-master/examples/Makefile
new file mode 100644
index 0000000..11ae2d0
--- /dev/null
+++ b/vendor/optparse-master/examples/Makefile
@@ -0,0 +1,18 @@
+CC = cc
+CFLAGS = -ansi -pedantic -Wall -Wextra -Wno-unused-function -Wno-unused-but-set-variable -g3
+LDFLAGS =
+LDLIBS =
+
+all: short$(EXE) long$(EXE) subcommands$(EXE)
+
+short$(EXE): short.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ short.c ../optparse.h $(LDLIBS)
+
+long$(EXE): long.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ long.c ../optparse.h $(LDLIBS)
+
+subcommands$(EXE): subcommands.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ subcommands.c ../optparse.h $(LDLIBS)
+
+clean:
+ rm -f short$(EXE) long$(EXE) subcommands$(EXE)
diff --git a/vendor/optparse-master/examples/long.c b/vendor/optparse-master/examples/long.c
new file mode 100644
index 0000000..00993fa
--- /dev/null
+++ b/vendor/optparse-master/examples/long.c
@@ -0,0 +1,56 @@
+/* This is free and unencumbered software released into the public domain. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define OPTPARSE_IMPLEMENTATION
+#define OPTPARSE_API static
+#include "../optparse.h"
+
+int main(int argc, char **argv)
+{
+ struct optparse_long longopts[] = {
+ {"amend", 'a', OPTPARSE_NONE},
+ {"brief", 'b', OPTPARSE_NONE},
+ {"color", 'c', OPTPARSE_REQUIRED},
+ {"delay", 'd', OPTPARSE_OPTIONAL},
+ {0}
+ };
+
+ bool amend = false;
+ bool brief = false;
+ const char *color = "white";
+ int delay = 0;
+
+ char *arg;
+ int option;
+ struct optparse options;
+
+ (void)argc;
+ optparse_init(&options, argv);
+ while ((option = optparse_long(&options, longopts, NULL)) != -1) {
+ switch (option) {
+ case 'a':
+ amend = true;
+ break;
+ case 'b':
+ brief = true;
+ break;
+ case 'c':
+ color = options.optarg;
+ break;
+ case 'd':
+ delay = options.optarg ? atoi(options.optarg) : 1;
+ break;
+ case '?':
+ fprintf(stderr, "%s: %s\n", argv[0], options.errmsg);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Print remaining arguments. */
+ while ((arg = optparse_arg(&options)))
+ printf("%s\n", arg);
+
+ return 0;
+}
diff --git a/vendor/optparse-master/examples/short.c b/vendor/optparse-master/examples/short.c
new file mode 100644
index 0000000..781ea8a
--- /dev/null
+++ b/vendor/optparse-master/examples/short.c
@@ -0,0 +1,47 @@
+/* This is free and unencumbered software released into the public domain. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define OPTPARSE_IMPLEMENTATION
+#define OPTPARSE_API static
+#include "../optparse.h"
+
+int main(int argc, char **argv)
+{
+ bool amend = false;
+ bool brief = false;
+ const char *color = "white";
+ int delay = 0;
+
+ char *arg;
+ int option;
+ struct optparse options;
+
+ (void)argc;
+ optparse_init(&options, argv);
+ while ((option = optparse(&options, "abc:d::")) != -1) {
+ switch (option) {
+ case 'a':
+ amend = true;
+ break;
+ case 'b':
+ brief = true;
+ break;
+ case 'c':
+ color = options.optarg;
+ break;
+ case 'd':
+ delay = options.optarg ? atoi(options.optarg) : 1;
+ break;
+ case '?':
+ fprintf(stderr, "%s: %s\n", argv[0], options.errmsg);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Print remaining arguments. */
+ while ((arg = optparse_arg(&options)))
+ printf("%s\n", arg);
+ return 0;
+}
diff --git a/vendor/optparse-master/examples/subcommands.c b/vendor/optparse-master/examples/subcommands.c
new file mode 100644
index 0000000..3d6238c
--- /dev/null
+++ b/vendor/optparse-master/examples/subcommands.c
@@ -0,0 +1,120 @@
+/* This is free and unencumbered software released into the public domain. */
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define OPTPARSE_IMPLEMENTATION
+#include "../optparse.h"
+
+static int cmd_echo(char **argv)
+{
+ int i, option;
+ bool newline = true;
+ struct optparse options;
+
+ optparse_init(&options, argv);
+ options.permute = 0;
+ while ((option = optparse(&options, "hn")) != -1) {
+ switch (option) {
+ case 'h':
+ puts("usage: echo [-hn] [ARG]...");
+ return 0;
+ case 'n':
+ newline = false;
+ break;
+ case '?':
+ fprintf(stderr, "%s: %s\n", argv[0], options.errmsg);
+ return 1;
+ }
+ }
+ argv += options.optind;
+
+ for (i = 0; argv[i]; i++) {
+ printf("%s%s", i ? " " : "", argv[i]);
+ }
+ if (newline) {
+ putchar('\n');
+ }
+
+ fflush(stdout);
+ return !!ferror(stdout);
+}
+
+static int cmd_sleep(char **argv)
+{
+ int i, option;
+ struct optparse options;
+
+ optparse_init(&options, argv);
+ while ((option = optparse(&options, "h")) != -1) {
+ switch (option) {
+ case 'h':
+ puts("usage: sleep [-h] [NUMBER]...");
+ return 0;
+ case '?':
+ fprintf(stderr, "%s: %s\n", argv[0], options.errmsg);
+ return 1;
+ }
+ }
+
+ for (i = 0; argv[i]; i++) {
+ if (sleep(atoi(argv[i]))) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+usage(FILE *f)
+{
+ fprintf(f, "usage: example [-h] <echo|sleep> [OPTION]...\n");
+}
+
+int main(int argc, char **argv)
+{
+ int i, option;
+ char **subargv;
+ struct optparse options;
+
+ static const struct {
+ char name[8];
+ int (*cmd)(char **);
+ } cmds[] = {
+ {"echo", cmd_echo },
+ {"sleep", cmd_sleep},
+ };
+ int ncmds = sizeof(cmds) / sizeof(*cmds);
+
+ (void)argc;
+ optparse_init(&options, argv);
+ options.permute = 0;
+ while ((option = optparse(&options, "h")) != -1) {
+ switch (option) {
+ case 'h':
+ usage(stdout);
+ return 0;
+ case '?':
+ usage(stderr);
+ fprintf(stderr, "%s: %s\n", argv[0], options.errmsg);
+ return 1;
+ }
+ }
+
+ subargv = argv + options.optind;
+ if (!subargv[0]) {
+ fprintf(stderr, "%s: missing subcommand\n", argv[0]);
+ usage(stderr);
+ return 1;
+ }
+
+ for (i = 0; i < ncmds; i++) {
+ if (!strcmp(cmds[i].name, subargv[0])) {
+ return cmds[i].cmd(subargv);
+ }
+ }
+ fprintf(stderr, "%s: invalid subcommand: %s\n", argv[0], subargv[0]);
+ return 1;
+}
diff --git a/vendor/optparse-master/optparse.h b/vendor/optparse-master/optparse.h
new file mode 100644
index 0000000..160d0fc
--- /dev/null
+++ b/vendor/optparse-master/optparse.h
@@ -0,0 +1,409 @@
+/* Optparse --- portable, reentrant, embeddable, getopt-like option parser
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * To get the implementation, define OPTPARSE_IMPLEMENTATION.
+ * Optionally define OPTPARSE_API to control the API's visibility
+ * and/or linkage (static, __attribute__, __declspec).
+ *
+ * The POSIX getopt() option parser has three fatal flaws. These flaws
+ * are solved by Optparse.
+ *
+ * 1) Parser state is stored entirely in global variables, some of
+ * which are static and inaccessible. This means only one thread can
+ * use getopt(). It also means it's not possible to recursively parse
+ * nested sub-arguments while in the middle of argument parsing.
+ * Optparse fixes this by storing all state on a local struct.
+ *
+ * 2) The POSIX standard provides no way to properly reset the parser.
+ * This means for portable code that getopt() is only good for one
+ * run, over one argv with one option string. It also means subcommand
+ * options cannot be processed with getopt(). Most implementations
+ * provide a method to reset the parser, but it's not portable.
+ * Optparse provides an optparse_arg() function for stepping over
+ * subcommands and continuing parsing of options with another option
+ * string. The Optparse struct itself can be passed around to
+ * subcommand handlers for additional subcommand option parsing. A
+ * full reset can be achieved by with an additional optparse_init().
+ *
+ * 3) Error messages are printed to stderr. This can be disabled with
+ * opterr, but the messages themselves are still inaccessible.
+ * Optparse solves this by writing an error message in its errmsg
+ * field. The downside to Optparse is that this error message will
+ * always be in English rather than the current locale.
+ *
+ * Optparse should be familiar with anyone accustomed to getopt(), and
+ * it could be a nearly drop-in replacement. The option string is the
+ * same and the fields have the same names as the getopt() global
+ * variables (optarg, optind, optopt).
+ *
+ * Optparse also supports GNU-style long options with optparse_long().
+ * The interface is slightly different and simpler than getopt_long().
+ *
+ * By default, argv is permuted as it is parsed, moving non-option
+ * arguments to the end. This can be disabled by setting the `permute`
+ * field to 0 after initialization.
+ */
+#ifndef OPTPARSE_H
+#define OPTPARSE_H
+
+#ifndef OPTPARSE_API
+# define OPTPARSE_API
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+struct optparse {
+ char **argv;
+ int permute;
+ int optind;
+ int optopt;
+ char *optarg;
+ char errmsg[64];
+ int subopt;
+};
+
+enum optparse_argtype {
+ OPTPARSE_NONE,
+ OPTPARSE_REQUIRED,
+ OPTPARSE_OPTIONAL
+};
+
+struct optparse_long {
+ const char *longname;
+ int shortname;
+ enum optparse_argtype argtype;
+};
+
+/**
+ * Initializes the parser state.
+ */
+OPTPARSE_API
+void optparse_init(struct optparse *options, char **argv);
+
+/**
+ * Read the next option in the argv array.
+ * @param optstring a getopt()-formatted option string.
+ * @return the next option character, -1 for done, or '?' for error
+ *
+ * Just like getopt(), a character followed by no colons means no
+ * argument. One colon means the option has a required argument. Two
+ * colons means the option takes an optional argument.
+ */
+OPTPARSE_API
+int optparse(struct optparse *options, const char *optstring);
+
+/**
+ * Handles GNU-style long options in addition to getopt() options.
+ * This works a lot like GNU's getopt_long(). The last option in
+ * longopts must be all zeros, marking the end of the array. The
+ * longindex argument may be NULL.
+ */
+OPTPARSE_API
+int optparse_long(struct optparse *options,
+ const struct optparse_long *longopts,
+ int *longindex);
+
+/**
+ * Used for stepping over non-option arguments.
+ * @return the next non-option argument, or NULL for no more arguments
+ *
+ * Argument parsing can continue with optparse() after using this
+ * function. That would be used to parse the options for the
+ * subcommand returned by optparse_arg(). This function allows you to
+ * ignore the value of optind.
+ */
+OPTPARSE_API
+char *optparse_arg(struct optparse *options);
+
+/* Implementation */
+#ifdef OPTPARSE_IMPLEMENTATION
+
+#define OPTPARSE_MSG_INVALID "invalid option"
+#define OPTPARSE_MSG_MISSING "option requires an argument"
+#define OPTPARSE_MSG_TOOMANY "option takes no arguments"
+
+static int
+optparse_error(struct optparse *options, const char *msg, const char *data)
+{
+ unsigned p = 0;
+ const char *sep = " -- '";
+ while (*msg)
+ options->errmsg[p++] = *msg++;
+ while (*sep)
+ options->errmsg[p++] = *sep++;
+ while (p < sizeof(options->errmsg) - 2 && *data)
+ options->errmsg[p++] = *data++;
+ options->errmsg[p++] = '\'';
+ options->errmsg[p++] = '\0';
+ return '?';
+}
+
+OPTPARSE_API
+void
+optparse_init(struct optparse *options, char **argv)
+{
+ options->argv = argv;
+ options->permute = 1;
+ options->optind = argv[0] != 0;
+ options->subopt = 0;
+ options->optarg = 0;
+ options->errmsg[0] = '\0';
+}
+
+static int
+optparse_is_dashdash(const char *arg)
+{
+ return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] == '\0';
+}
+
+static int
+optparse_is_shortopt(const char *arg)
+{
+ return arg != 0 && arg[0] == '-' && arg[1] != '-' && arg[1] != '\0';
+}
+
+static int
+optparse_is_longopt(const char *arg)
+{
+ return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] != '\0';
+}
+
+static void
+optparse_permute(struct optparse *options, int index)
+{
+ char *nonoption = options->argv[index];
+ int i;
+ for (i = index; i < options->optind - 1; i++)
+ options->argv[i] = options->argv[i + 1];
+ options->argv[options->optind - 1] = nonoption;
+}
+
+static int
+optparse_argtype(const char *optstring, char c)
+{
+ int count = OPTPARSE_NONE;
+ if (c == ':')
+ return -1;
+ for (; *optstring && c != *optstring; optstring++);
+ if (!*optstring)
+ return -1;
+ if (optstring[1] == ':')
+ count += optstring[2] == ':' ? 2 : 1;
+ return count;
+}
+
+OPTPARSE_API
+int
+optparse(struct optparse *options, const char *optstring)
+{
+ int type;
+ char *next;
+ char *option = options->argv[options->optind];
+ options->errmsg[0] = '\0';
+ options->optopt = 0;
+ options->optarg = 0;
+ if (option == 0) {
+ return -1;
+ } else if (optparse_is_dashdash(option)) {
+ options->optind++; /* consume "--" */
+ return -1;
+ } else if (!optparse_is_shortopt(option)) {
+ if (options->permute) {
+ int index = options->optind++;
+ int r = optparse(options, optstring);
+ optparse_permute(options, index);
+ options->optind--;
+ return r;
+ } else {
+ return -1;
+ }
+ }
+ option += options->subopt + 1;
+ options->optopt = option[0];
+ type = optparse_argtype(optstring, option[0]);
+ next = options->argv[options->optind + 1];
+ switch (type) {
+ case -1: {
+ char str[2] = {0, 0};
+ str[0] = option[0];
+ options->optind++;
+ return optparse_error(options, OPTPARSE_MSG_INVALID, str);
+ }
+ case OPTPARSE_NONE:
+ if (option[1]) {
+ options->subopt++;
+ } else {
+ options->subopt = 0;
+ options->optind++;
+ }
+ return option[0];
+ case OPTPARSE_REQUIRED:
+ options->subopt = 0;
+ options->optind++;
+ if (option[1]) {
+ options->optarg = option + 1;
+ } else if (next != 0) {
+ options->optarg = next;
+ options->optind++;
+ } else {
+ char str[2] = {0, 0};
+ str[0] = option[0];
+ options->optarg = 0;
+ return optparse_error(options, OPTPARSE_MSG_MISSING, str);
+ }
+ return option[0];
+ case OPTPARSE_OPTIONAL:
+ options->subopt = 0;
+ options->optind++;
+ if (option[1])
+ options->optarg = option + 1;
+ else
+ options->optarg = 0;
+ return option[0];
+ }
+ return 0;
+}
+
+OPTPARSE_API
+char *
+optparse_arg(struct optparse *options)
+{
+ char *option = options->argv[options->optind];
+ options->subopt = 0;
+ if (option != 0)
+ options->optind++;
+ return option;
+}
+
+static int
+optparse_longopts_end(const struct optparse_long *longopts, int i)
+{
+ return !longopts[i].longname && !longopts[i].shortname;
+}
+
+static void
+optparse_from_long(const struct optparse_long *longopts, char *optstring)
+{
+ char *p = optstring;
+ int i;
+ for (i = 0; !optparse_longopts_end(longopts, i); i++) {
+ if (longopts[i].shortname && longopts[i].shortname < 127) {
+ int a;
+ *p++ = longopts[i].shortname;
+ for (a = 0; a < (int)longopts[i].argtype; a++)
+ *p++ = ':';
+ }
+ }
+ *p = '\0';
+}
+
+/* Unlike strcmp(), handles options containing "=". */
+static int
+optparse_longopts_match(const char *longname, const char *option)
+{
+ const char *a = option, *n = longname;
+ if (longname == 0)
+ return 0;
+ for (; *a && *n && *a != '='; a++, n++)
+ if (*a != *n)
+ return 0;
+ return *n == '\0' && (*a == '\0' || *a == '=');
+}
+
+/* Return the part after "=", or NULL. */
+static char *
+optparse_longopts_arg(char *option)
+{
+ for (; *option && *option != '='; option++);
+ if (*option == '=')
+ return option + 1;
+ else
+ return 0;
+}
+
+static int
+optparse_long_fallback(struct optparse *options,
+ const struct optparse_long *longopts,
+ int *longindex)
+{
+ int result;
+ char optstring[96 * 3 + 1]; /* 96 ASCII printable characters */
+ optparse_from_long(longopts, optstring);
+ result = optparse(options, optstring);
+ if (longindex != 0) {
+ *longindex = -1;
+ if (result != -1) {
+ int i;
+ for (i = 0; !optparse_longopts_end(longopts, i); i++)
+ if (longopts[i].shortname == options->optopt)
+ *longindex = i;
+ }
+ }
+ return result;
+}
+
+OPTPARSE_API
+int
+optparse_long(struct optparse *options,
+ const struct optparse_long *longopts,
+ int *longindex)
+{
+ int i;
+ char *option = options->argv[options->optind];
+ if (option == 0) {
+ return -1;
+ } else if (optparse_is_dashdash(option)) {
+ options->optind++; /* consume "--" */
+ return -1;
+ } else if (optparse_is_shortopt(option)) {
+ return optparse_long_fallback(options, longopts, longindex);
+ } else if (!optparse_is_longopt(option)) {
+ if (options->permute) {
+ int index = options->optind++;
+ int r = optparse_long(options, longopts, longindex);
+ optparse_permute(options, index);
+ options->optind--;
+ return r;
+ } else {
+ return -1;
+ }
+ }
+
+ /* Parse as long option. */
+ options->errmsg[0] = '\0';
+ options->optopt = 0;
+ options->optarg = 0;
+ option += 2; /* skip "--" */
+ options->optind++;
+ for (i = 0; !optparse_longopts_end(longopts, i); i++) {
+ const char *name = longopts[i].longname;
+ if (optparse_longopts_match(name, option)) {
+ char *arg;
+ if (longindex)
+ *longindex = i;
+ options->optopt = longopts[i].shortname;
+ arg = optparse_longopts_arg(option);
+ if (longopts[i].argtype == OPTPARSE_NONE && arg != 0) {
+ return optparse_error(options, OPTPARSE_MSG_TOOMANY, name);
+ } if (arg != 0) {
+ options->optarg = arg;
+ } else if (longopts[i].argtype == OPTPARSE_REQUIRED) {
+ options->optarg = options->argv[options->optind];
+ if (options->optarg == 0)
+ return optparse_error(options, OPTPARSE_MSG_MISSING, name);
+ else
+ options->optind++;
+ }
+ return options->optopt;
+ }
+ }
+ return optparse_error(options, OPTPARSE_MSG_INVALID, option);
+}
+
+#endif /* OPTPARSE_IMPLEMENTATION */
+
+#pragma GCC diagnostic pop
+
+#endif /* OPTPARSE_H */
diff --git a/vendor/optparse-master/test.c b/vendor/optparse-master/test.c
new file mode 100644
index 0000000..bc613db
--- /dev/null
+++ b/vendor/optparse-master/test.c
@@ -0,0 +1,302 @@
+#define OPTPARSE_IMPLEMENTATION
+#define OPTPARSE_API static
+#include "optparse.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void
+print_argv(char **argv)
+{
+ while (*argv) {
+ printf("%s ", *argv++);
+ }
+ printf("\n");
+}
+
+static void
+try_optparse(char **argv)
+{
+ int opt;
+ char *arg;
+ struct optparse options;
+
+ print_argv(argv);
+ optparse_init(&options, argv);
+ while ((opt = optparse(&options, "abc:d::")) != -1) {
+ if (opt == '?') {
+ printf("%s: %s\n", argv[0], options.errmsg);
+ }
+ printf("%c (%d) = '%s'\n", opt, options.optind, options.optarg);
+ }
+ printf("optind = %d\n", options.optind);
+ while ((arg = optparse_arg(&options))) {
+ printf("argument: %s\n", arg);
+ }
+}
+
+static void
+try_optparse_long(char **argv)
+{
+ char *arg;
+ int opt, longindex;
+ struct optparse options;
+ struct optparse_long longopts[] = {
+ {"amend", 'a', OPTPARSE_NONE},
+ {"brief", 'b', OPTPARSE_NONE},
+ {"color", 'c', OPTPARSE_REQUIRED},
+ {"delay", 'd', OPTPARSE_OPTIONAL},
+ {"erase", 256, OPTPARSE_REQUIRED},
+ {0, 0, 0}
+ };
+
+ print_argv(argv);
+ optparse_init(&options, argv);
+ while ((opt = optparse_long(&options, longopts, &longindex)) != -1) {
+ char buf[2] = {0, 0};
+ if (opt == '?') {
+ printf("%s: %s\n", argv[0], options.errmsg);
+ }
+ buf[0] = opt;
+ printf("%-6s(%d, %d) = '%s'\n",
+ opt < 127 ? buf : longopts[longindex].longname,
+ options.optind, longindex, options.optarg);
+ }
+ printf("optind = %d\n", options.optind);
+ while ((arg = optparse_arg(&options))) {
+ printf("argument: %s\n", arg);
+ }
+}
+
+static int
+manual_test(int argc, char **argv)
+{
+ size_t size = (argc + 1) * sizeof(*argv);
+ char **argv_copy = malloc(size);
+
+ memcpy(argv_copy, argv, size);
+ printf("\nOPTPARSE\n");
+ try_optparse(argv_copy);
+
+ printf("\nOPTPARSE LONG\n");
+ try_optparse_long(argv);
+ return 0;
+}
+
+static int
+testsuite(void)
+{
+ struct config {
+ char amend;
+ char brief;
+ char *color;
+ int delay;
+ int erase;
+ };
+ struct {
+ char *argv[8];
+ struct config conf;
+ char *args[8];
+ char *err;
+ } t[] = {
+ {
+ {"", "--", "foobar", 0},
+ {0, 0, 0, 0, 0},
+ {"foobar", 0},
+ 0
+ },
+ {
+ {"", "-a", "-b", "-c", "-d", "10", "-e", 0},
+ {1, 1, "", 10, 1},
+ {0},
+ 0
+ },
+ {
+ {
+ "",
+ "--amend",
+ "--brief",
+ "--color",
+ "--delay",
+ "10",
+ "--erase",
+ 0
+ },
+ {1, 1, "", 10, 1},
+ {0},
+ 0
+ },
+ {
+ {"", "-a", "-b", "-cred", "-d", "10", "-e", 0},
+ {1, 1, "red", 10, 1},
+ {0},
+ 0
+ },
+ {
+ {"", "-abcblue", "-d10", "foobar", 0},
+ {1, 1, "blue", 10, 0},
+ {"foobar", 0},
+ 0
+ },
+ {
+ {"", "--color=red", "-d", "10", "--", "foobar", 0},
+ {0, 0, "red", 10, 0},
+ {"foobar", 0},
+ 0
+ },
+ {
+ {"", "-eeeeee", 0},
+ {0, 0, 0, 0, 6},
+ {0},
+ 0
+ },
+ {
+ {"", "--delay", 0},
+ {0, 0, 0, 0, 0},
+ {0},
+ OPTPARSE_MSG_MISSING
+ },
+ {
+ {"", "--foo", "bar", 0},
+ {0, 0, 0, 0, 0},
+ {"--foo", "bar", 0},
+ OPTPARSE_MSG_INVALID
+ },
+ {
+ {"", "-x", 0},
+ {0, 0, 0, 0, 0},
+ {"-x", 0},
+ OPTPARSE_MSG_INVALID
+ },
+ {
+ {"", "-", 0},
+ {0, 0, 0, 0, 0},
+ {"-", 0},
+ 0
+ },
+ {
+ {"", "-e", "foo", "bar", "baz", "-a", "quux", 0},
+ {1, 0, 0, 0, 1},
+ {"foo", "bar", "baz", "quux", 0},
+ 0
+ },
+ {
+ {"", "foo", "--delay", "1234", "bar", "-cred", 0},
+ {0, 0, "red", 1234, 0},
+ {"foo", "bar", 0},
+ 0
+ },
+ };
+ int ntests = sizeof(t) / sizeof(*t);
+ int i, nfails = 0;
+ struct optparse_long longopts[] = {
+ {"amend", 'a', OPTPARSE_NONE},
+ {"brief", 'b', OPTPARSE_NONE},
+ {"color", 'c', OPTPARSE_OPTIONAL},
+ {"delay", 'd', OPTPARSE_REQUIRED},
+ {"erase", 'e', OPTPARSE_NONE},
+ {0, 0, 0}
+ };
+
+ for (i = 0; i < ntests; i++) {
+ int j, opt, longindex;
+ char *arg, *err = 0;
+ struct optparse options;
+ struct config conf = {0, 0, 0, 0, 0};
+
+ optparse_init(&options, t[i].argv);
+ while ((opt = optparse_long(&options, longopts, &longindex)) != -1) {
+ switch (opt) {
+ case 'a': conf.amend = 1; break;
+ case 'b': conf.brief = 1; break;
+ case 'c': conf.color = options.optarg ? options.optarg : ""; break;
+ case 'd': conf.delay = atoi(options.optarg); break;
+ case 'e': conf.erase++; break;
+ default: err = options.errmsg;
+ }
+ }
+
+ if (conf.amend != t[i].conf.amend) {
+ nfails++;
+ printf("FAIL (%2d): expected amend %d, got %d\n",
+ i, t[i].conf.amend, conf.amend);
+ }
+
+ if (conf.brief != t[i].conf.brief) {
+ nfails++;
+ printf("FAIL (%2d): expected brief %d, got %d\n",
+ i, t[i].conf.brief, conf.brief);
+ }
+
+ if (t[i].conf.color) {
+ if (!conf.color || strcmp(conf.color, t[i].conf.color)) {
+ nfails++;
+ printf("FAIL (%2d): expected color %s, got %s\n",
+ i, t[i].conf.color, conf.color ? conf.color : "(nil)");
+ }
+ } else {
+ if (conf.color) {
+ nfails++;
+ printf("FAIL (%2d): expected no color, got %s\n",
+ i, conf.color);
+ }
+ }
+
+ if (conf.delay != t[i].conf.delay) {
+ nfails++;
+ printf("FAIL (%2d): expected delay %d, got %d\n",
+ i, t[i].conf.delay, conf.delay);
+ }
+
+ if (conf.erase != t[i].conf.erase) {
+ nfails++;
+ printf("FAIL (%2d): expected erase %d, got %d\n",
+ i, t[i].conf.erase, conf.erase);
+ }
+
+ if (t[i].err) {
+ if (!err || strncmp(err, t[i].err, strlen(t[i].err))) {
+ nfails++;
+ printf("FAIL (%2d): expected error '%s', got %s\n",
+ i, t[i].err, err && err[0] ? err : "(nil)");
+ }
+
+ } else {
+ if (err) {
+ nfails++;
+ printf("FAIL (%2d): expected no error, got %s\n",
+ i, err);
+ }
+
+ for (j = 0; t[i].args[j]; j++) {
+ arg = optparse_arg(&options);
+ if (!arg || strcmp(arg, t[i].args[j])) {
+ nfails++;
+ printf("FAIL (%2d): expected arg %s, got %s\n",
+ i, t[i].args[j], arg ? arg : "(nil)");
+ }
+ }
+ if ((arg = optparse_arg(&options))) {
+ nfails++;
+ printf("FAIL (%2d): expected no more args, got %s\n",
+ i, arg);
+ }
+ }
+ }
+
+ if (nfails == 0) {
+ puts("All tests pass.");
+ }
+ return nfails != 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ if (argc > 1) {
+ return manual_test(argc, argv);
+ } else {
+ return testsuite();
+ }
+}