forked from cory/tildefriends
xopt => getopt_long. I give up on xopt. It didn't help me as much as I had hoped, and I had problems building for mingw with only some versions of GCC. Not worth any further time.
This commit is contained in:
parent
4cb82d81b7
commit
8c13f5dbba
16
GNUmakefile
16
GNUmakefile
@ -245,7 +245,6 @@ $(APP_OBJS): CFLAGS += \
|
|||||||
-Ideps/quickjs \
|
-Ideps/quickjs \
|
||||||
-Ideps/sqlite \
|
-Ideps/sqlite \
|
||||||
-Ideps/valgrind \
|
-Ideps/valgrind \
|
||||||
-Ideps/xopt \
|
|
||||||
-Wdouble-promotion \
|
-Wdouble-promotion \
|
||||||
-Werror
|
-Werror
|
||||||
ifeq ($(UNAME_M),x86_64)
|
ifeq ($(UNAME_M),x86_64)
|
||||||
@ -497,18 +496,6 @@ $(SQLITE_OBJS): CFLAGS += \
|
|||||||
-Wno-unused-function \
|
-Wno-unused-function \
|
||||||
-Wno-unused-variable
|
-Wno-unused-variable
|
||||||
|
|
||||||
XOPT_SOURCES := deps/xopt/xopt.c
|
|
||||||
XOPT_OBJS := $(call get_objs,XOPT_SOURCES)
|
|
||||||
$(filter $(BUILD_DIR)/win%,$(XOPT_OBJS)): CFLAGS += \
|
|
||||||
-DHAVE_SNPRINTF \
|
|
||||||
-DHAVE_VSNPRINTF \
|
|
||||||
-DHAVE_VASNPRINTF \
|
|
||||||
-DHAVE_VASPRINTF \
|
|
||||||
-Dvsnprintf=rpl_vsnprintf
|
|
||||||
$(XOPT_OBJS): CFLAGS += \
|
|
||||||
-Wno-implicit-const-int-float-conversion \
|
|
||||||
-Wno-pointer-to-int-cast
|
|
||||||
|
|
||||||
QUICKJS_SOURCES := \
|
QUICKJS_SOURCES := \
|
||||||
deps/quickjs/cutils.c \
|
deps/quickjs/cutils.c \
|
||||||
deps/quickjs/libbf.c \
|
deps/quickjs/libbf.c \
|
||||||
@ -637,8 +624,7 @@ ALL_APP_OBJS := \
|
|||||||
$(QUICKJS_OBJS) \
|
$(QUICKJS_OBJS) \
|
||||||
$(SODIUM_OBJS) \
|
$(SODIUM_OBJS) \
|
||||||
$(SQLITE_OBJS) \
|
$(SQLITE_OBJS) \
|
||||||
$(UV_OBJS) \
|
$(UV_OBJS)
|
||||||
$(XOPT_OBJS)
|
|
||||||
|
|
||||||
DEPS = $(ALL_APP_OBJS:.o=.d)
|
DEPS = $(ALL_APP_OBJS:.o=.d)
|
||||||
-include $(DEPS)
|
-include $(DEPS)
|
||||||
|
17
deps/xopt/.circleci/Dockerfile.test
vendored
17
deps/xopt/.circleci/Dockerfile.test
vendored
@ -1,17 +0,0 @@
|
|||||||
FROM alpine:3.7 AS base
|
|
||||||
WORKDIR /src
|
|
||||||
RUN apk --update add alpine-sdk cmake bash
|
|
||||||
COPY . ./
|
|
||||||
WORKDIR /src/build
|
|
||||||
|
|
||||||
# Debug
|
|
||||||
FROM base
|
|
||||||
RUN cmake .. -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=On
|
|
||||||
RUN cmake --build .
|
|
||||||
RUN ctest -VV
|
|
||||||
|
|
||||||
# Release
|
|
||||||
FROM base
|
|
||||||
RUN cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=On
|
|
||||||
RUN cmake --build .
|
|
||||||
RUN ctest -VV
|
|
7
deps/xopt/.circleci/config.yml
vendored
7
deps/xopt/.circleci/config.yml
vendored
@ -1,7 +0,0 @@
|
|||||||
version: 2
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
machine: true
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: docker build -f .circleci/Dockerfile.test .
|
|
1
deps/xopt/.dockerignore
vendored
1
deps/xopt/.dockerignore
vendored
@ -1 +0,0 @@
|
|||||||
.gitignore
|
|
18
deps/xopt/.editorconfig
vendored
18
deps/xopt/.editorconfig
vendored
@ -1,18 +0,0 @@
|
|||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
indent_style = tab
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
[*.coffee]
|
|
||||||
indent_style = space
|
|
||||||
|
|
||||||
[{package.json,*.yml}]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.md]
|
|
||||||
trim_trailing_whitespace = false
|
|
6
deps/xopt/.gitignore
vendored
6
deps/xopt/.gitignore
vendored
@ -1,6 +0,0 @@
|
|||||||
*.sw[a-p]
|
|
||||||
/bin/
|
|
||||||
/build/
|
|
||||||
/.tup/
|
|
||||||
/*.o
|
|
||||||
/*.a
|
|
43
deps/xopt/CMakeLists.txt
vendored
43
deps/xopt/CMakeLists.txt
vendored
@ -1,43 +0,0 @@
|
|||||||
cmake_minimum_required (VERSION 3.8)
|
|
||||||
project (xopt)
|
|
||||||
|
|
||||||
add_library (xopt STATIC "${CMAKE_CURRENT_SOURCE_DIR}/xopt.c")
|
|
||||||
|
|
||||||
if (APPLE OR UNIX)
|
|
||||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic -std=c11 -D_XOPEN_SOURCE=600 -fdiagnostics-color=always -fvisibility=hidden")
|
|
||||||
set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g3 -O0")
|
|
||||||
set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
function (_xopt_test name)
|
|
||||||
if (NOT TARGET "xopt-test-${name}")
|
|
||||||
add_executable ("xopt-test-${name}" "${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.c")
|
|
||||||
target_link_libraries ("xopt-test-${name}" xopt)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set (testname "xopt-${name}-test")
|
|
||||||
set (testnum 1)
|
|
||||||
|
|
||||||
while (TEST "${testname}-${testnum}")
|
|
||||||
math (EXPR testnum "${testnum}+1")
|
|
||||||
endwhile ()
|
|
||||||
|
|
||||||
add_test (
|
|
||||||
NAME "${testname}-${testnum}"
|
|
||||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test/test-case.sh" $<TARGET_FILE:xopt-test-${name}> "${CMAKE_CURRENT_SOURCE_DIR}/test/${name}-${testnum}.out" ${ARGN}
|
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/test")
|
|
||||||
endfunction ()
|
|
||||||
|
|
||||||
if (BUILD_TESTING)
|
|
||||||
enable_testing ()
|
|
||||||
_xopt_test (simple --some-int=10 --some-double=14.5 foo bar -- --some-other=20)
|
|
||||||
_xopt_test (macro --some-int=10 --some-double=14.5 foo bar -- --some-other=20)
|
|
||||||
_xopt_test (required --some-int=10 --some-double=14.5 --some-required=1337 foo bar -- --some-other=20)
|
|
||||||
_xopt_test (optional-longarg -i 10 -d 14.5 foo bar -- --some-other=20)
|
|
||||||
_xopt_test (autohelp --help -- --is-not-passed ignoreme)
|
|
||||||
_xopt_test (sloppyshorts -i10 -d 14.5 "-ssome string" -m -mm -mmm foo bar -- --is-not-passed ignoreme)
|
|
||||||
_xopt_test (nocondense-sloppy -i 10 -d 14.5 -s "some string" -m -mm -mmm foo bar -- --is-not-passed ignoreme)
|
|
||||||
_xopt_test (nocondense-sloppy -i 10 -d 14.5 "-ssome string" -m -mm -mmm foo bar -- --is-not-passed ignoreme)
|
|
||||||
_xopt_test (nocondense-sloppy -i 10 -d 14.5 "-ssome string" -m -m -m -m -m -m foo bar -- --is-not-passed ignoreme)
|
|
||||||
_xopt_test (nocondense -i 10 -d 14.5 "-ssome string" -m -mm -mmm foo bar -- --is-not-passed ignoreme)
|
|
||||||
endif ()
|
|
9
deps/xopt/README.md
vendored
9
deps/xopt/README.md
vendored
@ -1,9 +0,0 @@
|
|||||||
# XOpt [![CircleCI](https://circleci.com/gh/Qix-/xopt.svg?style=svg)](https://circleci.com/gh/Qix-/xopt)
|
|
||||||
The sane answer to POpt.
|
|
||||||
|
|
||||||
XOpt is a command line argument parsing library written in ANSI C. XOpt
|
|
||||||
accepts arguments in GNU format and focuses on clean definition, taking stress
|
|
||||||
off the implementation.
|
|
||||||
|
|
||||||
# License
|
|
||||||
Originally by Josh Junon, released under [CC0](https://creativecommons.org/publicdomain/zero/1.0/). Go nuts.
|
|
2099
deps/xopt/snprintf.c
vendored
2099
deps/xopt/snprintf.c
vendored
File diff suppressed because it is too large
Load Diff
2
deps/xopt/test/.gitignore
vendored
2
deps/xopt/test/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
/*-test
|
|
||||||
/*.o
|
|
12
deps/xopt/test/autohelp-1.out
vendored
12
deps/xopt/test/autohelp-1.out
vendored
@ -1,12 +0,0 @@
|
|||||||
args: «--help» «--» «--is-not-passed» «ignoreme»
|
|
||||||
|
|
||||||
usage: autohelp-test-case [opts...] [--] [extras...]
|
|
||||||
|
|
||||||
Tests the simple parser macro
|
|
||||||
|
|
||||||
-i, --some-int=n Some integer value. Can set to whatever number you like.
|
|
||||||
-f Some float value.
|
|
||||||
--some-double=n Some double value.
|
|
||||||
-?, --help Shows this help message
|
|
||||||
|
|
||||||
[end of arguments]
|
|
100
deps/xopt/test/autohelp.c
vendored
100
deps/xopt/test/autohelp.c
vendored
@ -1,100 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "../xopt.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int someInt;
|
|
||||||
float someFloat;
|
|
||||||
double someDouble;
|
|
||||||
bool help;
|
|
||||||
} SimpleConfig;
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
|
||||||
{
|
|
||||||
"some-int",
|
|
||||||
'i',
|
|
||||||
offsetof(SimpleConfig, someInt),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_INT,
|
|
||||||
"n",
|
|
||||||
"Some integer value. Can set to whatever number you like."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
'f',
|
|
||||||
offsetof(SimpleConfig, someFloat),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_FLOAT,
|
|
||||||
"n",
|
|
||||||
"Some float value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-double",
|
|
||||||
0,
|
|
||||||
offsetof(SimpleConfig, someDouble),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_DOUBLE,
|
|
||||||
"n",
|
|
||||||
"Some double value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"help",
|
|
||||||
'?',
|
|
||||||
offsetof(SimpleConfig, help),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_BOOL,
|
|
||||||
0,
|
|
||||||
"Shows this help message"
|
|
||||||
},
|
|
||||||
XOPT_NULLOPTION
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
|
||||||
int exit_code = 1;
|
|
||||||
const char *err = NULL;
|
|
||||||
SimpleConfig config;
|
|
||||||
const char **extras = NULL;
|
|
||||||
int extraCount = 0;
|
|
||||||
|
|
||||||
/* show arguments */
|
|
||||||
fputs("args:", stderr);
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
fprintf(stderr, " «%s»", argv[i]);
|
|
||||||
}
|
|
||||||
fputs("\n\n", stderr);
|
|
||||||
|
|
||||||
/* setup defaults */
|
|
||||||
config.someInt = 0;
|
|
||||||
config.someDouble = 0.0;
|
|
||||||
config.help = 0;
|
|
||||||
|
|
||||||
XOPT_SIMPLE_PARSE(
|
|
||||||
"autohelp-test-case",
|
|
||||||
0,
|
|
||||||
&options[0], &config,
|
|
||||||
argc, argv,
|
|
||||||
&extraCount, &extras,
|
|
||||||
&err,
|
|
||||||
stderr,
|
|
||||||
"[opts...] [--] [extras...]",
|
|
||||||
"Tests the simple parser macro",
|
|
||||||
"[end of arguments]",
|
|
||||||
15);
|
|
||||||
|
|
||||||
if (!err) {
|
|
||||||
err = config.help
|
|
||||||
? "--help was passed but autohelp didn't fire"
|
|
||||||
: "--help was not passed - it is required for this test case";
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
|
||||||
|
|
||||||
exit:
|
|
||||||
free(extras); /* DO NOT free individual strings */
|
|
||||||
return exit_code;
|
|
||||||
xopt_help:
|
|
||||||
exit_code = 0;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
11
deps/xopt/test/macro-1.out
vendored
11
deps/xopt/test/macro-1.out
vendored
@ -1,11 +0,0 @@
|
|||||||
args: «--some-int=10» «--some-double=14.5» «foo» «bar» «--» «--some-other=20»
|
|
||||||
|
|
||||||
someInt: 10
|
|
||||||
someFloat: 0.000000
|
|
||||||
someDouble: 14.500000
|
|
||||||
help: 0
|
|
||||||
|
|
||||||
extra count: 3
|
|
||||||
- foo
|
|
||||||
- bar
|
|
||||||
- --some-other=20
|
|
116
deps/xopt/test/macro.c
vendored
116
deps/xopt/test/macro.c
vendored
@ -1,116 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "../xopt.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int someInt;
|
|
||||||
float someFloat;
|
|
||||||
double someDouble;
|
|
||||||
bool help;
|
|
||||||
} SimpleConfig;
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
|
||||||
{
|
|
||||||
"some-int",
|
|
||||||
'i',
|
|
||||||
offsetof(SimpleConfig, someInt),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_INT,
|
|
||||||
"n",
|
|
||||||
"Some integer value. Can set to whatever number you like."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-float",
|
|
||||||
'f',
|
|
||||||
offsetof(SimpleConfig, someFloat),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_FLOAT,
|
|
||||||
"n",
|
|
||||||
"Some float value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-double",
|
|
||||||
'd',
|
|
||||||
offsetof(SimpleConfig, someDouble),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_DOUBLE,
|
|
||||||
"n",
|
|
||||||
"Some double value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"help",
|
|
||||||
'?',
|
|
||||||
offsetof(SimpleConfig, help),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_BOOL,
|
|
||||||
0,
|
|
||||||
"Shows this help message"
|
|
||||||
},
|
|
||||||
XOPT_NULLOPTION
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
|
||||||
int exit_code = 1;
|
|
||||||
const char *err = NULL;
|
|
||||||
SimpleConfig config;
|
|
||||||
const char **extras = NULL;
|
|
||||||
const char **extrasPtr = NULL;
|
|
||||||
int extraCount = 0;
|
|
||||||
|
|
||||||
/* show arguments */
|
|
||||||
fputs("args:", stderr);
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
fprintf(stderr, " «%s»", argv[i]);
|
|
||||||
}
|
|
||||||
fputs("\n\n", stderr);
|
|
||||||
|
|
||||||
/* setup defaults */
|
|
||||||
config.someInt = 0;
|
|
||||||
config.someDouble = 0.0;
|
|
||||||
config.help = 0;
|
|
||||||
|
|
||||||
XOPT_SIMPLE_PARSE(
|
|
||||||
argv[0],
|
|
||||||
0,
|
|
||||||
&options[0], &config,
|
|
||||||
argc, argv,
|
|
||||||
&extraCount, &extras,
|
|
||||||
&err,
|
|
||||||
stderr,
|
|
||||||
"[opts...] [--] [extras...]",
|
|
||||||
"Tests the simple parser macro",
|
|
||||||
"[end of arguments]",
|
|
||||||
15);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print */
|
|
||||||
#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \
|
|
||||||
config.field)
|
|
||||||
|
|
||||||
P(someInt, d);
|
|
||||||
P(someFloat, f);
|
|
||||||
P(someDouble, f);
|
|
||||||
P(help, d);
|
|
||||||
|
|
||||||
fprintf(stderr, "\nextra count: %d\n", extraCount);
|
|
||||||
extrasPtr = extras;
|
|
||||||
while (extraCount--) {
|
|
||||||
fprintf(stderr, "- %s\n", *extrasPtr++);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef P
|
|
||||||
|
|
||||||
exit_code = 0;
|
|
||||||
exit:
|
|
||||||
free(extras); /* DO NOT free individual strings */
|
|
||||||
return exit_code;
|
|
||||||
xopt_help:
|
|
||||||
exit_code = 2;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
3
deps/xopt/test/nocondense-1.out
vendored
3
deps/xopt/test/nocondense-1.out
vendored
@ -1,3 +0,0 @@
|
|||||||
args: «-i» «10» «-d» «14.5» «-ssome string» «-m» «-mm» «-mmm» «foo» «bar» «--» «--is-not-passed» «ignoreme»
|
|
||||||
|
|
||||||
Error: short option parameters must be separated, not condensed: -ssome string
|
|
3
deps/xopt/test/nocondense-sloppy-1.out
vendored
3
deps/xopt/test/nocondense-sloppy-1.out
vendored
@ -1,3 +0,0 @@
|
|||||||
args: «-i» «10» «-d» «14.5» «-s» «some string» «-m» «-mm» «-mmm» «foo» «bar» «--» «--is-not-passed» «ignoreme»
|
|
||||||
|
|
||||||
Error: short options cannot be combined: -mm
|
|
3
deps/xopt/test/nocondense-sloppy-2.out
vendored
3
deps/xopt/test/nocondense-sloppy-2.out
vendored
@ -1,3 +0,0 @@
|
|||||||
args: «-i» «10» «-d» «14.5» «-ssome string» «-m» «-mm» «-mmm» «foo» «bar» «--» «--is-not-passed» «ignoreme»
|
|
||||||
|
|
||||||
Error: short options cannot be combined: -mm
|
|
14
deps/xopt/test/nocondense-sloppy-3.out
vendored
14
deps/xopt/test/nocondense-sloppy-3.out
vendored
@ -1,14 +0,0 @@
|
|||||||
args: «-i» «10» «-d» «14.5» «-ssome string» «-m» «-m» «-m» «-m» «-m» «-m» «foo» «bar» «--» «--is-not-passed» «ignoreme»
|
|
||||||
|
|
||||||
someInt: 10
|
|
||||||
someFloat: 0.000000
|
|
||||||
someDouble: 14.500000
|
|
||||||
someString: some string
|
|
||||||
multiCount: 6
|
|
||||||
help: 0
|
|
||||||
|
|
||||||
extra count: 4
|
|
||||||
- foo
|
|
||||||
- bar
|
|
||||||
- --is-not-passed
|
|
||||||
- ignoreme
|
|
149
deps/xopt/test/nocondense-sloppy.c
vendored
149
deps/xopt/test/nocondense-sloppy.c
vendored
@ -1,149 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "../xopt.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int someInt;
|
|
||||||
float someFloat;
|
|
||||||
double someDouble;
|
|
||||||
const char *someString;
|
|
||||||
int multiCount;
|
|
||||||
bool help;
|
|
||||||
} SimpleConfig;
|
|
||||||
|
|
||||||
static void on_verbose(const char *v, void *data, const struct xoptOption *option, bool longArg, const char **err) {
|
|
||||||
(void) v;
|
|
||||||
(void) longArg;
|
|
||||||
(void) err;
|
|
||||||
int *count = (int *)(((char *) data) + option->offset);
|
|
||||||
++*count;
|
|
||||||
}
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
|
||||||
{
|
|
||||||
"some-int",
|
|
||||||
'i',
|
|
||||||
offsetof(SimpleConfig, someInt),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_INT,
|
|
||||||
"n",
|
|
||||||
"Some integer value. Can set to whatever number you like."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-float",
|
|
||||||
'f',
|
|
||||||
offsetof(SimpleConfig, someFloat),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_FLOAT,
|
|
||||||
"n",
|
|
||||||
"Some float value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-double",
|
|
||||||
'd',
|
|
||||||
offsetof(SimpleConfig, someDouble),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_DOUBLE,
|
|
||||||
"n",
|
|
||||||
"Some double value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-string",
|
|
||||||
's',
|
|
||||||
offsetof(SimpleConfig, someString),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_STRING,
|
|
||||||
"s",
|
|
||||||
"Some string value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
'm',
|
|
||||||
offsetof(SimpleConfig, multiCount),
|
|
||||||
&on_verbose,
|
|
||||||
XOPT_TYPE_BOOL,
|
|
||||||
0,
|
|
||||||
"Specify multiple times to increase count"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"help",
|
|
||||||
'?',
|
|
||||||
offsetof(SimpleConfig, help),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_BOOL,
|
|
||||||
0,
|
|
||||||
"Shows this help message"
|
|
||||||
},
|
|
||||||
XOPT_NULLOPTION
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
|
||||||
int exit_code = 1;
|
|
||||||
const char *err = NULL;
|
|
||||||
SimpleConfig config;
|
|
||||||
const char **extras = NULL;
|
|
||||||
const char **extrasPtr = NULL;
|
|
||||||
int extraCount = 0;
|
|
||||||
|
|
||||||
/* show arguments */
|
|
||||||
fputs("args:", stderr);
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
fprintf(stderr, " «%s»", argv[i]);
|
|
||||||
}
|
|
||||||
fputs("\n\n", stderr);
|
|
||||||
|
|
||||||
/* setup defaults */
|
|
||||||
config.someInt = 0;
|
|
||||||
config.someDouble = 0.0;
|
|
||||||
config.someFloat = 0.0f;
|
|
||||||
config.someString = 0;
|
|
||||||
config.multiCount = 0;
|
|
||||||
config.help = 0;
|
|
||||||
|
|
||||||
XOPT_SIMPLE_PARSE(
|
|
||||||
argv[0],
|
|
||||||
XOPT_CTX_SLOPPYSHORTS | XOPT_CTX_NOCONDENSE,
|
|
||||||
&options[0], &config,
|
|
||||||
argc, argv,
|
|
||||||
&extraCount, &extras,
|
|
||||||
&err,
|
|
||||||
stderr,
|
|
||||||
"[opts...] [--] [extras...]",
|
|
||||||
"Tests the simple parser macro",
|
|
||||||
"[end of arguments]",
|
|
||||||
15);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print */
|
|
||||||
#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \
|
|
||||||
config.field)
|
|
||||||
|
|
||||||
P(someInt, d);
|
|
||||||
P(someFloat, f);
|
|
||||||
P(someDouble, f);
|
|
||||||
P(someString, s);
|
|
||||||
P(multiCount, d);
|
|
||||||
P(help, d);
|
|
||||||
|
|
||||||
fprintf(stderr, "\nextra count: %d\n", extraCount);
|
|
||||||
extrasPtr = extras;
|
|
||||||
while (extraCount--) {
|
|
||||||
fprintf(stderr, "- %s\n", *extrasPtr++);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef P
|
|
||||||
|
|
||||||
exit_code = 0;
|
|
||||||
exit:
|
|
||||||
free(extras); /* DO NOT free individual strings */
|
|
||||||
return exit_code;
|
|
||||||
xopt_help:
|
|
||||||
exit_code = 2;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
149
deps/xopt/test/nocondense.c
vendored
149
deps/xopt/test/nocondense.c
vendored
@ -1,149 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "../xopt.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int someInt;
|
|
||||||
float someFloat;
|
|
||||||
double someDouble;
|
|
||||||
const char *someString;
|
|
||||||
int multiCount;
|
|
||||||
bool help;
|
|
||||||
} SimpleConfig;
|
|
||||||
|
|
||||||
static void on_verbose(const char *v, void *data, const struct xoptOption *option, bool longArg, const char **err) {
|
|
||||||
(void) v;
|
|
||||||
(void) longArg;
|
|
||||||
(void) err;
|
|
||||||
int *count = (int *)(((char *) data) + option->offset);
|
|
||||||
++*count;
|
|
||||||
}
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
|
||||||
{
|
|
||||||
"some-int",
|
|
||||||
'i',
|
|
||||||
offsetof(SimpleConfig, someInt),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_INT,
|
|
||||||
"n",
|
|
||||||
"Some integer value. Can set to whatever number you like."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-float",
|
|
||||||
'f',
|
|
||||||
offsetof(SimpleConfig, someFloat),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_FLOAT,
|
|
||||||
"n",
|
|
||||||
"Some float value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-double",
|
|
||||||
'd',
|
|
||||||
offsetof(SimpleConfig, someDouble),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_DOUBLE,
|
|
||||||
"n",
|
|
||||||
"Some double value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-string",
|
|
||||||
's',
|
|
||||||
offsetof(SimpleConfig, someString),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_STRING,
|
|
||||||
"s",
|
|
||||||
"Some string value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
'm',
|
|
||||||
offsetof(SimpleConfig, multiCount),
|
|
||||||
&on_verbose,
|
|
||||||
XOPT_TYPE_BOOL,
|
|
||||||
0,
|
|
||||||
"Specify multiple times to increase count"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"help",
|
|
||||||
'?',
|
|
||||||
offsetof(SimpleConfig, help),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_BOOL,
|
|
||||||
0,
|
|
||||||
"Shows this help message"
|
|
||||||
},
|
|
||||||
XOPT_NULLOPTION
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
|
||||||
int exit_code = 1;
|
|
||||||
const char *err = NULL;
|
|
||||||
SimpleConfig config;
|
|
||||||
const char **extras = NULL;
|
|
||||||
const char **extrasPtr = NULL;
|
|
||||||
int extraCount = 0;
|
|
||||||
|
|
||||||
/* show arguments */
|
|
||||||
fputs("args:", stderr);
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
fprintf(stderr, " «%s»", argv[i]);
|
|
||||||
}
|
|
||||||
fputs("\n\n", stderr);
|
|
||||||
|
|
||||||
/* setup defaults */
|
|
||||||
config.someInt = 0;
|
|
||||||
config.someDouble = 0.0;
|
|
||||||
config.someFloat = 0.0f;
|
|
||||||
config.someString = 0;
|
|
||||||
config.multiCount = 0;
|
|
||||||
config.help = 0;
|
|
||||||
|
|
||||||
XOPT_SIMPLE_PARSE(
|
|
||||||
argv[0],
|
|
||||||
XOPT_CTX_NOCONDENSE,
|
|
||||||
&options[0], &config,
|
|
||||||
argc, argv,
|
|
||||||
&extraCount, &extras,
|
|
||||||
&err,
|
|
||||||
stderr,
|
|
||||||
"[opts...] [--] [extras...]",
|
|
||||||
"Tests the simple parser macro",
|
|
||||||
"[end of arguments]",
|
|
||||||
15);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print */
|
|
||||||
#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \
|
|
||||||
config.field)
|
|
||||||
|
|
||||||
P(someInt, d);
|
|
||||||
P(someFloat, f);
|
|
||||||
P(someDouble, f);
|
|
||||||
P(someString, s);
|
|
||||||
P(multiCount, d);
|
|
||||||
P(help, d);
|
|
||||||
|
|
||||||
fprintf(stderr, "\nextra count: %d\n", extraCount);
|
|
||||||
extrasPtr = extras;
|
|
||||||
while (extraCount--) {
|
|
||||||
fprintf(stderr, "- %s\n", *extrasPtr++);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef P
|
|
||||||
|
|
||||||
exit_code = 0;
|
|
||||||
exit:
|
|
||||||
free(extras); /* DO NOT free individual strings */
|
|
||||||
return exit_code;
|
|
||||||
xopt_help:
|
|
||||||
exit_code = 2;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
11
deps/xopt/test/optional-longarg-1.out
vendored
11
deps/xopt/test/optional-longarg-1.out
vendored
@ -1,11 +0,0 @@
|
|||||||
args: «-i» «10» «-d» «14.5» «foo» «bar» «--» «--some-other=20»
|
|
||||||
|
|
||||||
someInt: 10
|
|
||||||
someFloat: 0.000000
|
|
||||||
someDouble: 14.500000
|
|
||||||
help: 0
|
|
||||||
|
|
||||||
extra count: 3
|
|
||||||
- foo
|
|
||||||
- bar
|
|
||||||
- --some-other=20
|
|
116
deps/xopt/test/optional-longarg.c
vendored
116
deps/xopt/test/optional-longarg.c
vendored
@ -1,116 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "../xopt.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int someInt;
|
|
||||||
float someFloat;
|
|
||||||
double someDouble;
|
|
||||||
bool help;
|
|
||||||
} SimpleConfig;
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
'i',
|
|
||||||
offsetof(SimpleConfig, someInt),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_INT,
|
|
||||||
"n",
|
|
||||||
"Some integer value. Can set to whatever number you like."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
'f',
|
|
||||||
offsetof(SimpleConfig, someFloat),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_FLOAT,
|
|
||||||
"n",
|
|
||||||
"Some float value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
'd',
|
|
||||||
offsetof(SimpleConfig, someDouble),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_DOUBLE,
|
|
||||||
"n",
|
|
||||||
"Some double value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"help",
|
|
||||||
'?',
|
|
||||||
offsetof(SimpleConfig, help),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_BOOL,
|
|
||||||
0,
|
|
||||||
"Shows this help message"
|
|
||||||
},
|
|
||||||
XOPT_NULLOPTION
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
|
||||||
int exit_code = 1;
|
|
||||||
const char *err = NULL;
|
|
||||||
SimpleConfig config;
|
|
||||||
const char **extras = NULL;
|
|
||||||
const char **extrasPtr = NULL;
|
|
||||||
int extraCount = 0;
|
|
||||||
|
|
||||||
/* show arguments */
|
|
||||||
fputs("args:", stderr);
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
fprintf(stderr, " «%s»", argv[i]);
|
|
||||||
}
|
|
||||||
fputs("\n\n", stderr);
|
|
||||||
|
|
||||||
/* setup defaults */
|
|
||||||
config.someInt = 0;
|
|
||||||
config.someDouble = 0.0;
|
|
||||||
config.help = 0;
|
|
||||||
|
|
||||||
XOPT_SIMPLE_PARSE(
|
|
||||||
argv[0],
|
|
||||||
0,
|
|
||||||
&options[0], &config,
|
|
||||||
argc, argv,
|
|
||||||
&extraCount, &extras,
|
|
||||||
&err,
|
|
||||||
stderr,
|
|
||||||
"macro-test [opts...] [--] [extras...]",
|
|
||||||
"Tests the simple parser macro",
|
|
||||||
"[end of arguments]",
|
|
||||||
15);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print */
|
|
||||||
#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \
|
|
||||||
config.field)
|
|
||||||
|
|
||||||
P(someInt, d);
|
|
||||||
P(someFloat, f);
|
|
||||||
P(someDouble, f);
|
|
||||||
P(help, d);
|
|
||||||
|
|
||||||
fprintf(stderr, "\nextra count: %d\n", extraCount);
|
|
||||||
extrasPtr = extras;
|
|
||||||
while (extraCount--) {
|
|
||||||
fprintf(stderr, "- %s\n", *extrasPtr++);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef P
|
|
||||||
|
|
||||||
exit_code = 0;
|
|
||||||
exit:
|
|
||||||
free(extras); /* DO NOT free individual strings */
|
|
||||||
return exit_code;
|
|
||||||
xopt_help:
|
|
||||||
exit_code = 2;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
12
deps/xopt/test/required-1.out
vendored
12
deps/xopt/test/required-1.out
vendored
@ -1,12 +0,0 @@
|
|||||||
args: «--some-int=10» «--some-double=14.5» «--some-required=1337» «foo» «bar» «--» «--some-other=20»
|
|
||||||
|
|
||||||
someInt: 10
|
|
||||||
someFloat: 0.000000
|
|
||||||
someDouble: 14.500000
|
|
||||||
someRequired: 1337
|
|
||||||
help: 0
|
|
||||||
|
|
||||||
extra count: 3
|
|
||||||
- foo
|
|
||||||
- bar
|
|
||||||
- --some-other=20
|
|
128
deps/xopt/test/required.c
vendored
128
deps/xopt/test/required.c
vendored
@ -1,128 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "../xopt.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int someInt;
|
|
||||||
float someFloat;
|
|
||||||
double someDouble;
|
|
||||||
int someRequired;
|
|
||||||
bool help;
|
|
||||||
} SimpleConfig;
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
|
||||||
{
|
|
||||||
"some-int",
|
|
||||||
'i',
|
|
||||||
offsetof(SimpleConfig, someInt),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_INT,
|
|
||||||
"n",
|
|
||||||
"Some integer value. Can set to whatever number you like."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-float",
|
|
||||||
'f',
|
|
||||||
offsetof(SimpleConfig, someFloat),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_FLOAT,
|
|
||||||
"n",
|
|
||||||
"Some float value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-double",
|
|
||||||
'd',
|
|
||||||
offsetof(SimpleConfig, someDouble),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_DOUBLE,
|
|
||||||
"n",
|
|
||||||
"Some double value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-required",
|
|
||||||
'r',
|
|
||||||
offsetof(SimpleConfig, someRequired),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_INT | XOPT_REQUIRED,
|
|
||||||
"n",
|
|
||||||
"Some value"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"help",
|
|
||||||
'?',
|
|
||||||
offsetof(SimpleConfig, help),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_BOOL,
|
|
||||||
0,
|
|
||||||
"Shows this help message"
|
|
||||||
},
|
|
||||||
XOPT_NULLOPTION
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
|
||||||
int exit_code = 1;
|
|
||||||
const char *err = NULL;
|
|
||||||
SimpleConfig config;
|
|
||||||
const char **extras = NULL;
|
|
||||||
const char **extrasPtr = NULL;
|
|
||||||
int extraCount = 0;
|
|
||||||
|
|
||||||
/* show arguments */
|
|
||||||
fputs("args:", stderr);
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
fprintf(stderr, " «%s»", argv[i]);
|
|
||||||
}
|
|
||||||
fputs("\n\n", stderr);
|
|
||||||
|
|
||||||
/* setup defaults */
|
|
||||||
config.someInt = 0;
|
|
||||||
config.someDouble = 0.0;
|
|
||||||
config.someRequired = 0;
|
|
||||||
config.help = 0;
|
|
||||||
|
|
||||||
XOPT_SIMPLE_PARSE(
|
|
||||||
argv[0],
|
|
||||||
0,
|
|
||||||
&options[0], &config,
|
|
||||||
argc, argv,
|
|
||||||
&extraCount, &extras,
|
|
||||||
&err,
|
|
||||||
stderr,
|
|
||||||
"[opts...] [--] [extras...]",
|
|
||||||
"Tests the simple parser macro",
|
|
||||||
"[end of arguments]",
|
|
||||||
15);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print */
|
|
||||||
#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \
|
|
||||||
config.field)
|
|
||||||
|
|
||||||
P(someInt, d);
|
|
||||||
P(someFloat, f);
|
|
||||||
P(someDouble, f);
|
|
||||||
P(someRequired, d);
|
|
||||||
P(help, d);
|
|
||||||
|
|
||||||
fprintf(stderr, "\nextra count: %d\n", extraCount);
|
|
||||||
extrasPtr = extras;
|
|
||||||
while (extraCount--) {
|
|
||||||
fprintf(stderr, "- %s\n", *extrasPtr++);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef P
|
|
||||||
|
|
||||||
exit_code = 0;
|
|
||||||
exit:
|
|
||||||
free(extras); /* DO NOT free individual strings */
|
|
||||||
return exit_code;
|
|
||||||
xopt_help:
|
|
||||||
exit_code = 2;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
11
deps/xopt/test/simple-1.out
vendored
11
deps/xopt/test/simple-1.out
vendored
@ -1,11 +0,0 @@
|
|||||||
args: «--some-int=10» «--some-double=14.5» «foo» «bar» «--» «--some-other=20»
|
|
||||||
|
|
||||||
someInt: 10
|
|
||||||
someFloat: 0.000000
|
|
||||||
someDouble: 14.500000
|
|
||||||
help: 0
|
|
||||||
|
|
||||||
extra count: 3
|
|
||||||
- foo
|
|
||||||
- bar
|
|
||||||
- --some-other=20
|
|
128
deps/xopt/test/simple.c
vendored
128
deps/xopt/test/simple.c
vendored
@ -1,128 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "../xopt.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int someInt;
|
|
||||||
float someFloat;
|
|
||||||
double someDouble;
|
|
||||||
bool help;
|
|
||||||
} SimpleConfig;
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
|
||||||
{
|
|
||||||
"some-int",
|
|
||||||
'i',
|
|
||||||
offsetof(SimpleConfig, someInt),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_INT,
|
|
||||||
"n",
|
|
||||||
"Some integer value. Can set to whatever number you like."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-float",
|
|
||||||
'f',
|
|
||||||
offsetof(SimpleConfig, someFloat),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_FLOAT,
|
|
||||||
"n",
|
|
||||||
"Some float value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-double",
|
|
||||||
'd',
|
|
||||||
offsetof(SimpleConfig, someDouble),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_DOUBLE,
|
|
||||||
"n",
|
|
||||||
"Some double value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"help",
|
|
||||||
'?',
|
|
||||||
offsetof(SimpleConfig, help),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_BOOL,
|
|
||||||
0,
|
|
||||||
"Shows this help message"
|
|
||||||
},
|
|
||||||
XOPT_NULLOPTION
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
|
||||||
int result;
|
|
||||||
const char *err;
|
|
||||||
xoptContext *ctx;
|
|
||||||
SimpleConfig config;
|
|
||||||
const char **extras = 0;
|
|
||||||
const char **extrasPtr = 0;
|
|
||||||
int extraCount;
|
|
||||||
|
|
||||||
result = 0;
|
|
||||||
err = 0;
|
|
||||||
|
|
||||||
/* show arguments */
|
|
||||||
fputs("args:", stderr);
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
fprintf(stderr, " «%s»", argv[i]);
|
|
||||||
}
|
|
||||||
fputs("\n\n", stderr);
|
|
||||||
|
|
||||||
/* setup defaults */
|
|
||||||
config.someInt = 0;
|
|
||||||
config.someDouble = 0.0;
|
|
||||||
config.help = 0;
|
|
||||||
|
|
||||||
/* create context */
|
|
||||||
ctx = xopt_context("xopt-test", options,
|
|
||||||
XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, &err);
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
|
||||||
result = 1;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* parse */
|
|
||||||
extraCount = xopt_parse(ctx, argc, argv, &config, &extras, &err);
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
|
||||||
result = 2;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* help? */
|
|
||||||
if (config.help) {
|
|
||||||
xoptAutohelpOptions opts;
|
|
||||||
opts.usage = "[options] [extras...]";
|
|
||||||
opts.prefix = "A simple demonstration of the XOpt options parser library.";
|
|
||||||
opts.suffix = "End argument list.";
|
|
||||||
opts.spacer = 10;
|
|
||||||
|
|
||||||
xopt_autohelp(ctx, stderr, &opts, &err);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print */
|
|
||||||
#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \
|
|
||||||
config.field)
|
|
||||||
|
|
||||||
P(someInt, d);
|
|
||||||
P(someFloat, f);
|
|
||||||
P(someDouble, f);
|
|
||||||
P(help, d);
|
|
||||||
|
|
||||||
fprintf(stderr, "\nextra count: %d\n", extraCount);
|
|
||||||
extrasPtr = extras;
|
|
||||||
while (extraCount--) {
|
|
||||||
fprintf(stderr, "- %s\n", *extrasPtr++);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef P
|
|
||||||
|
|
||||||
exit:
|
|
||||||
if (extras) free(extras); /* DO NOT free individual strings */
|
|
||||||
if (ctx) free(ctx); /* they point to argv strings */
|
|
||||||
return result;
|
|
||||||
}
|
|
14
deps/xopt/test/sloppyshorts-1.out
vendored
14
deps/xopt/test/sloppyshorts-1.out
vendored
@ -1,14 +0,0 @@
|
|||||||
args: «-i10» «-d» «14.5» «-ssome string» «-m» «-mm» «-mmm» «foo» «bar» «--» «--is-not-passed» «ignoreme»
|
|
||||||
|
|
||||||
someInt: 10
|
|
||||||
someFloat: 0.000000
|
|
||||||
someDouble: 14.500000
|
|
||||||
someString: some string
|
|
||||||
multiCount: 6
|
|
||||||
help: 0
|
|
||||||
|
|
||||||
extra count: 4
|
|
||||||
- foo
|
|
||||||
- bar
|
|
||||||
- --is-not-passed
|
|
||||||
- ignoreme
|
|
149
deps/xopt/test/sloppyshorts.c
vendored
149
deps/xopt/test/sloppyshorts.c
vendored
@ -1,149 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "../xopt.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int someInt;
|
|
||||||
float someFloat;
|
|
||||||
double someDouble;
|
|
||||||
const char *someString;
|
|
||||||
int multiCount;
|
|
||||||
bool help;
|
|
||||||
} SimpleConfig;
|
|
||||||
|
|
||||||
static void on_verbose(const char *v, void *data, const struct xoptOption *option, bool longArg, const char **err) {
|
|
||||||
(void) v;
|
|
||||||
(void) longArg;
|
|
||||||
(void) err;
|
|
||||||
int *count = (int *)(((char *) data) + option->offset);
|
|
||||||
++*count;
|
|
||||||
}
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
|
||||||
{
|
|
||||||
"some-int",
|
|
||||||
'i',
|
|
||||||
offsetof(SimpleConfig, someInt),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_INT,
|
|
||||||
"n",
|
|
||||||
"Some integer value. Can set to whatever number you like."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-float",
|
|
||||||
'f',
|
|
||||||
offsetof(SimpleConfig, someFloat),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_FLOAT,
|
|
||||||
"n",
|
|
||||||
"Some float value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-double",
|
|
||||||
'd',
|
|
||||||
offsetof(SimpleConfig, someDouble),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_DOUBLE,
|
|
||||||
"n",
|
|
||||||
"Some double value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"some-string",
|
|
||||||
's',
|
|
||||||
offsetof(SimpleConfig, someString),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_STRING,
|
|
||||||
"s",
|
|
||||||
"Some string value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
'm',
|
|
||||||
offsetof(SimpleConfig, multiCount),
|
|
||||||
&on_verbose,
|
|
||||||
XOPT_TYPE_BOOL,
|
|
||||||
0,
|
|
||||||
"Specify multiple times to increase count"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"help",
|
|
||||||
'?',
|
|
||||||
offsetof(SimpleConfig, help),
|
|
||||||
0,
|
|
||||||
XOPT_TYPE_BOOL,
|
|
||||||
0,
|
|
||||||
"Shows this help message"
|
|
||||||
},
|
|
||||||
XOPT_NULLOPTION
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
|
||||||
int exit_code = 1;
|
|
||||||
const char *err = NULL;
|
|
||||||
SimpleConfig config;
|
|
||||||
const char **extras = NULL;
|
|
||||||
const char **extrasPtr = NULL;
|
|
||||||
int extraCount = 0;
|
|
||||||
|
|
||||||
/* show arguments */
|
|
||||||
fputs("args:", stderr);
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
fprintf(stderr, " «%s»", argv[i]);
|
|
||||||
}
|
|
||||||
fputs("\n\n", stderr);
|
|
||||||
|
|
||||||
/* setup defaults */
|
|
||||||
config.someInt = 0;
|
|
||||||
config.someDouble = 0.0;
|
|
||||||
config.someFloat = 0.0f;
|
|
||||||
config.someString = 0;
|
|
||||||
config.multiCount = 0;
|
|
||||||
config.help = 0;
|
|
||||||
|
|
||||||
XOPT_SIMPLE_PARSE(
|
|
||||||
argv[0],
|
|
||||||
XOPT_CTX_SLOPPYSHORTS,
|
|
||||||
&options[0], &config,
|
|
||||||
argc, argv,
|
|
||||||
&extraCount, &extras,
|
|
||||||
&err,
|
|
||||||
stderr,
|
|
||||||
"[opts...] [--] [extras...]",
|
|
||||||
"Tests the simple parser macro",
|
|
||||||
"[end of arguments]",
|
|
||||||
15);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print */
|
|
||||||
#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \
|
|
||||||
config.field)
|
|
||||||
|
|
||||||
P(someInt, d);
|
|
||||||
P(someFloat, f);
|
|
||||||
P(someDouble, f);
|
|
||||||
P(someString, s);
|
|
||||||
P(multiCount, d);
|
|
||||||
P(help, d);
|
|
||||||
|
|
||||||
fprintf(stderr, "\nextra count: %d\n", extraCount);
|
|
||||||
extrasPtr = extras;
|
|
||||||
while (extraCount--) {
|
|
||||||
fprintf(stderr, "- %s\n", *extrasPtr++);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef P
|
|
||||||
|
|
||||||
exit_code = 0;
|
|
||||||
exit:
|
|
||||||
free(extras); /* DO NOT free individual strings */
|
|
||||||
return exit_code;
|
|
||||||
xopt_help:
|
|
||||||
exit_code = 2;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
46
deps/xopt/test/test-case.sh
vendored
46
deps/xopt/test/test-case.sh
vendored
@ -1,46 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
#
|
|
||||||
# To be used with CMake builds located in <xopt>/build/
|
|
||||||
#
|
|
||||||
|
|
||||||
set -uo pipefail
|
|
||||||
exec >&2
|
|
||||||
|
|
||||||
casebin="$1"
|
|
||||||
caseout="$2"
|
|
||||||
shift 2
|
|
||||||
|
|
||||||
function die {
|
|
||||||
echo -e "error: $*"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
if [ -z "$casebin" ]; then
|
|
||||||
die 'no test case executable specified'
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$caseout" ]; then
|
|
||||||
die 'no test case output (some-case.out) specified'
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -x "$casebin" ]; then
|
|
||||||
die "test case does not exist or is not executable: $casebin"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f "$caseout" ]; then
|
|
||||||
die "test case expected output file does not exist: $caseout"
|
|
||||||
fi
|
|
||||||
|
|
||||||
output="$("$casebin" "$@" 2>&1)"
|
|
||||||
r=$?
|
|
||||||
if [ $r -eq 139 ]; then
|
|
||||||
die "xopt test case failed with SEGFAULT ($r)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
diff="$(diff -U0 -d -t "$caseout" - <<< "$output" 2>&1)"
|
|
||||||
if [ ! -z "$diff" ]; then
|
|
||||||
die "xopt test case didn't match expected output: '$caseout'\n$diff"
|
|
||||||
fi
|
|
584
deps/xopt/xopt.c
vendored
584
deps/xopt/xopt.c
vendored
@ -1,584 +0,0 @@
|
|||||||
/**
|
|
||||||
* XOpt - command line parsing library
|
|
||||||
*
|
|
||||||
* Copyright (c) 2015-2019 Josh Junon
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* 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 OR COPYRIGHT HOLDERS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef XOPT_NOSTANDARD
|
|
||||||
# define HAVE_STDARG_H 1
|
|
||||||
# define HAVE_STDLIB_H 1
|
|
||||||
# define HAVE_ASPRINTF_H 1
|
|
||||||
# define vasprintf rpl_vasprintf
|
|
||||||
# ifndef _GNU_SOURCE
|
|
||||||
# define _GNU_SOURCE
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <setjmp.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "./xopt.h"
|
|
||||||
#include "./snprintf.c"
|
|
||||||
|
|
||||||
#define EXTRAS_INIT 10
|
|
||||||
#define ERRBUF_SIZE 1024 * 4
|
|
||||||
|
|
||||||
static char errbuf[ERRBUF_SIZE];
|
|
||||||
|
|
||||||
struct xoptContext {
|
|
||||||
const xoptOption *options;
|
|
||||||
long flags;
|
|
||||||
const char *name;
|
|
||||||
bool doubledash;
|
|
||||||
size_t options_count;
|
|
||||||
bool *required;
|
|
||||||
jmp_buf *jmp;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void _xopt_set_err(xoptContext *ctx, const char **err, const char *const fmt, ...);
|
|
||||||
static int _xopt_parse_arg(xoptContext *ctx, int argc, const char **argv,
|
|
||||||
int *argi, void *data, const char **err);
|
|
||||||
static void _xopt_assert_increment(xoptContext *ctx, const char ***extras, int extrasCount,
|
|
||||||
size_t *extrasCapac, const char **err);
|
|
||||||
static int _xopt_get_size(const char *arg);
|
|
||||||
static int _xopt_get_arg(const xoptContext *ctx, const char *arg, size_t len,
|
|
||||||
int size, const xoptOption **option, size_t *option_index);
|
|
||||||
static void _xopt_set(xoptContext *ctx, void *data, const xoptOption *option, const char *val,
|
|
||||||
bool longArg, const char **err);
|
|
||||||
static void _xopt_default_callback(const char *value, void *data,
|
|
||||||
const xoptOption *option, bool longArg, const char **err);
|
|
||||||
|
|
||||||
xoptContext* xopt_context(const char *name, const xoptOption *options, long flags,
|
|
||||||
const char **err) {
|
|
||||||
xoptContext* ctx;
|
|
||||||
*err = 0;
|
|
||||||
|
|
||||||
/* malloc context and check */
|
|
||||||
ctx = malloc(sizeof(xoptContext));
|
|
||||||
if (!ctx) {
|
|
||||||
ctx = 0;
|
|
||||||
_xopt_set_err(NULL, err, "could not allocate context");
|
|
||||||
} else {
|
|
||||||
const xoptOption *cur;
|
|
||||||
|
|
||||||
ctx->options = options;
|
|
||||||
ctx->flags = flags;
|
|
||||||
ctx->name = name;
|
|
||||||
ctx->doubledash = false;
|
|
||||||
ctx->required = NULL;
|
|
||||||
ctx->jmp = NULL;
|
|
||||||
|
|
||||||
ctx->options_count = 0;
|
|
||||||
cur = options;
|
|
||||||
for (; cur->longArg || cur->shortArg; cur++) ++ctx->options_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _xopt_parse_impl(xoptContext *ctx, int argc, const char **argv, void *data,
|
|
||||||
const char ***inextras, const char **err, int *extrasCount, size_t *extrasCapac,
|
|
||||||
const char ***extras, int *argi) {
|
|
||||||
int parseResult;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
*err = 0;
|
|
||||||
*argi = 0;
|
|
||||||
*extrasCount = 0;
|
|
||||||
*extrasCapac = EXTRAS_INIT;
|
|
||||||
*extras = malloc(sizeof(**extras) * EXTRAS_INIT);
|
|
||||||
|
|
||||||
jmp_buf jmp;
|
|
||||||
ctx->jmp = &jmp;
|
|
||||||
if (setjmp(jmp)) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check if extras malloc'd okay */
|
|
||||||
if (!*extras) {
|
|
||||||
_xopt_set_err(ctx, err, "could not allocate extras array");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* increment argument counter if we aren't
|
|
||||||
instructed to check argv[0] */
|
|
||||||
if (!(ctx->flags & XOPT_CTX_KEEPFIRST)) {
|
|
||||||
++(*argi);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set up required parameters list */
|
|
||||||
ctx->required = malloc(sizeof(*ctx->required) * ctx->options_count);
|
|
||||||
for (i = 0; i < ctx->options_count; i++) {
|
|
||||||
ctx->required[i] = (ctx->options[i].options & XOPT_REQUIRED) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* iterate over passed command line arguments */
|
|
||||||
for (; *argi < argc; (*argi)++) {
|
|
||||||
/* parse, breaking if there was a failure
|
|
||||||
parseResult is 0 if option, 1 if extra, or 2 if double-dash was encountered */
|
|
||||||
parseResult = _xopt_parse_arg(ctx, argc, argv, argi, data, err);
|
|
||||||
|
|
||||||
/* is the argument an extra? */
|
|
||||||
switch (parseResult) {
|
|
||||||
case 0: /* option */
|
|
||||||
/* make sure we're super-posix'd if specified to be
|
|
||||||
(check that no extras have been specified when an option is parsed,
|
|
||||||
enforcing options to be specific before [extra] arguments */
|
|
||||||
if ((ctx->flags & XOPT_CTX_POSIXMEHARDER) && *extrasCount) {
|
|
||||||
_xopt_set_err(ctx, err, "options cannot be specified after arguments: %s", argv[*argi]);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1: /* extra */
|
|
||||||
/* make sure we have enough room, or realloc if we don't -
|
|
||||||
check that it succeeded */
|
|
||||||
_xopt_assert_increment(ctx, extras, *extrasCount, extrasCapac, err);
|
|
||||||
|
|
||||||
/* add extra to list */
|
|
||||||
(*extras)[(*extrasCount)++] = argv[*argi];
|
|
||||||
break;
|
|
||||||
case 2: /* "--" was encountered */
|
|
||||||
/* nothing to do here - "--" was already handled for us */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
if (!*err) {
|
|
||||||
for (i = 0; i < ctx->options_count; i++) {
|
|
||||||
if (ctx->required[i]) {
|
|
||||||
const xoptOption *opt = &ctx->options[i];
|
|
||||||
if (opt->longArg) {
|
|
||||||
_xopt_set_err(ctx, err, "missing required option: --%s", opt->longArg);
|
|
||||||
} else {
|
|
||||||
_xopt_set_err(ctx, err, "missing required option: -%c", opt->shortArg);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ctx->required);
|
|
||||||
|
|
||||||
if (!*err) {
|
|
||||||
/* append null terminator to extras */
|
|
||||||
_xopt_assert_increment(ctx, extras, *extrasCount, extrasCapac, err);
|
|
||||||
if (!*err) {
|
|
||||||
(*extras)[*extrasCount] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*err) {
|
|
||||||
free(*extras);
|
|
||||||
*inextras = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*inextras = *extras;
|
|
||||||
return *extrasCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int xopt_parse(xoptContext *ctx, int argc, const char **argv, void *data,
|
|
||||||
const char ***inextras, const char **err) {
|
|
||||||
/* avoid longjmp clobbering */
|
|
||||||
int extrasCount;
|
|
||||||
size_t extrasCapac;
|
|
||||||
const char **extras;
|
|
||||||
int argi;
|
|
||||||
return _xopt_parse_impl(ctx, argc, argv, data, inextras, err, &extrasCount, &extrasCapac, &extras, &argi);
|
|
||||||
}
|
|
||||||
|
|
||||||
void xopt_autohelp(xoptContext *ctx, FILE *stream, const xoptAutohelpOptions *options,
|
|
||||||
const char **err) {
|
|
||||||
const xoptOption *o;
|
|
||||||
size_t i, width = 0, twidth;
|
|
||||||
const char *nl = "";
|
|
||||||
size_t spacer = options ? options->spacer : 2;
|
|
||||||
|
|
||||||
*err = 0;
|
|
||||||
|
|
||||||
/* make sure that if we ever write a call to _set_err() in the future here,
|
|
||||||
that we won't accidentally cause segfaults - we have an assertion in place
|
|
||||||
for ctx->jmp != NULL, so we make sure we'd trigger that assertion */
|
|
||||||
ctx->jmp = NULL;
|
|
||||||
|
|
||||||
if (options && options->usage) {
|
|
||||||
fprintf(stream, "%susage: %s %s\n", nl, ctx->name, options->usage);
|
|
||||||
nl = "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options && options->prefix) {
|
|
||||||
fprintf(stream, "%s%s\n\n", nl, options->prefix);
|
|
||||||
nl = "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find max width */
|
|
||||||
for (i = 0; ctx->options[i].longArg || ctx->options[i].shortArg; i++) {
|
|
||||||
o = &ctx->options[i];
|
|
||||||
twidth = 0;
|
|
||||||
if (o->longArg) {
|
|
||||||
twidth += 2 + strlen(o->longArg);
|
|
||||||
if (o->argDescrip) {
|
|
||||||
twidth += 1 + strlen(o->argDescrip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ctx->options[i].shortArg) {
|
|
||||||
twidth += 2;
|
|
||||||
}
|
|
||||||
if (ctx->options[i].shortArg && ctx->options[i].longArg) {
|
|
||||||
twidth += 2; /* `, ` */
|
|
||||||
}
|
|
||||||
|
|
||||||
width = width > twidth ? width : twidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print */
|
|
||||||
for (i = 0; ctx->options[i].longArg || ctx->options[i].shortArg; i++) {
|
|
||||||
o = &ctx->options[i];
|
|
||||||
twidth = 0;
|
|
||||||
if (o->shortArg) {
|
|
||||||
fprintf(stream, "-%c", o->shortArg);
|
|
||||||
twidth += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (o->shortArg && o->longArg) {
|
|
||||||
fprintf(stream, ", ");
|
|
||||||
twidth += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (o->longArg) {
|
|
||||||
fprintf(stream, "--%s", o->longArg);
|
|
||||||
twidth += 2 + strlen(o->longArg);
|
|
||||||
if (o->argDescrip) {
|
|
||||||
fprintf(stream, "=%s", o->argDescrip);
|
|
||||||
twidth += 1 + strlen(o->argDescrip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (o->descrip) {
|
|
||||||
for (; twidth < (width + spacer); twidth++) {
|
|
||||||
fprintf(stream, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (o->options & XOPT_REQUIRED) {
|
|
||||||
fprintf(stream, "(Required) %s\n", o->descrip);
|
|
||||||
} else {
|
|
||||||
fprintf(stream, "%s\n", o->descrip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options && options->suffix) {
|
|
||||||
fprintf(stream, "%s%s\n", nl, options->suffix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _xopt_set_err(xoptContext *ctx, const char **err, const char *const fmt, ...) {
|
|
||||||
va_list list;
|
|
||||||
va_start(list, fmt);
|
|
||||||
rpl_vsnprintf(&errbuf[0], ERRBUF_SIZE, fmt, list);
|
|
||||||
va_end(list);
|
|
||||||
*err = &errbuf[0];
|
|
||||||
|
|
||||||
if (ctx != NULL) {
|
|
||||||
assert(ctx->jmp != NULL);
|
|
||||||
longjmp(*ctx->jmp, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _xopt_parse_arg(xoptContext *ctx, int argc, const char **argv,
|
|
||||||
int *argi, void *data, const char **err) {
|
|
||||||
int size;
|
|
||||||
size_t length;
|
|
||||||
bool isExtra = false;
|
|
||||||
const xoptOption *option = NULL;
|
|
||||||
size_t option_index = 0;
|
|
||||||
const char* arg = argv[*argi];
|
|
||||||
|
|
||||||
/* are we in doubledash mode? */
|
|
||||||
if (ctx->doubledash) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get argument 'size' (long/short/extra) */
|
|
||||||
size = _xopt_get_size(arg);
|
|
||||||
|
|
||||||
/* adjust to parse from beginning of actual content */
|
|
||||||
arg += size;
|
|
||||||
length = strlen(arg);
|
|
||||||
|
|
||||||
if (size == 1 && length == 0) {
|
|
||||||
/* it's just a singular dash - treat it as an extra arg */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size == 2 && length == 0) {
|
|
||||||
/* double-dash - everything after this is an extra */
|
|
||||||
ctx->doubledash = 1;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (size) {
|
|
||||||
int argRequirement;
|
|
||||||
char *valStart;
|
|
||||||
case 1: /* short */
|
|
||||||
/* parse all */
|
|
||||||
while (length--) {
|
|
||||||
/* get argument or error if not found and strict mode enabled. */
|
|
||||||
argRequirement = _xopt_get_arg(ctx, arg++, 1, size, &option, &option_index);
|
|
||||||
if (!option) {
|
|
||||||
if (ctx->flags & XOPT_CTX_STRICT) {
|
|
||||||
_xopt_set_err(ctx, err, "invalid option: -%c", arg[-1]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argRequirement > 0 && length > 0 && !(ctx->flags & XOPT_CTX_SLOPPYSHORTS)) {
|
|
||||||
_xopt_set_err(ctx, err, "short option parameters must be separated, not condensed: %s", argv[*argi]);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (argRequirement) {
|
|
||||||
case 0: /* flag; doesn't take an argument */
|
|
||||||
if (length > 0 && (ctx->flags & XOPT_CTX_NOCONDENSE)) {
|
|
||||||
_xopt_set_err(ctx, err, "short options cannot be combined: %s", argv[*argi]);
|
|
||||||
}
|
|
||||||
|
|
||||||
_xopt_set(ctx, data, option, 0, false, err);
|
|
||||||
break;
|
|
||||||
case 1: /* argument is optional */
|
|
||||||
/* is there another argument, and is it a non-option? */
|
|
||||||
if (*argi + 1 < argc && _xopt_get_size(argv[*argi + 1]) == 0) {
|
|
||||||
_xopt_set(ctx, data, option, argv[++*argi], false, err);
|
|
||||||
} else {
|
|
||||||
_xopt_set(ctx, data, option, 0, false, err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2: /* requires an argument */
|
|
||||||
/* is it the last in a set of condensed options? */
|
|
||||||
if (length == 0) {
|
|
||||||
/* is there another argument? */
|
|
||||||
if (*argi + 1 < argc) {
|
|
||||||
/* is the next argument actually an option?
|
|
||||||
this indicates no value was passed */
|
|
||||||
if (_xopt_get_size(argv[*argi + 1])) {
|
|
||||||
_xopt_set_err(ctx, err, "missing option value: -%c",
|
|
||||||
option->shortArg);
|
|
||||||
} else {
|
|
||||||
_xopt_set(ctx, data, option, argv[++*argi], false, err);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_xopt_set_err(ctx, err, "missing option value: -%c",
|
|
||||||
option->shortArg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_xopt_set(ctx, data, option, arg, false, err);
|
|
||||||
length = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2: /* long */
|
|
||||||
/* find first equals sign */
|
|
||||||
valStart = strchr(arg, '=');
|
|
||||||
|
|
||||||
/* is there a value? */
|
|
||||||
if (valStart) {
|
|
||||||
/* we also increase valStart here in order to lop off
|
|
||||||
the equals sign */
|
|
||||||
length = valStart++ - arg;
|
|
||||||
|
|
||||||
/* but not really, if it's null */
|
|
||||||
if (!*valStart) {
|
|
||||||
valStart = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get the option */
|
|
||||||
argRequirement = _xopt_get_arg(ctx, arg, length, size, &option, &option_index);
|
|
||||||
if (!option) {
|
|
||||||
_xopt_set_err(ctx, err, "invalid option: --%.*s", length, arg);
|
|
||||||
} else {
|
|
||||||
switch (argRequirement) {
|
|
||||||
case 0: /* flag; doesn't take an argument */
|
|
||||||
if (valStart) {
|
|
||||||
_xopt_set_err(ctx, err, "option doesn't take a value: --%s", arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
_xopt_set(ctx, data, option, valStart, true, err);
|
|
||||||
break;
|
|
||||||
case 2: /* requires an argument */
|
|
||||||
if (!valStart) {
|
|
||||||
_xopt_set_err(ctx, err, "missing option value: --%s", arg);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
_xopt_set(ctx, data, option, valStart, true, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 0: /* extra */
|
|
||||||
isExtra = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option) {
|
|
||||||
/* indicate that we've seen this option and thus is no longer required */
|
|
||||||
ctx->required[option_index] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isExtra ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _xopt_assert_increment(xoptContext *ctx, const char ***extras, int extrasCount,
|
|
||||||
size_t *extrasCapac, const char **err) {
|
|
||||||
/* have we hit the list size limit? */
|
|
||||||
if ((size_t) extrasCount == *extrasCapac) {
|
|
||||||
/* increase capcity, realloc, and check for success */
|
|
||||||
*extrasCapac += EXTRAS_INIT;
|
|
||||||
*extras = realloc(*extras, sizeof(**extras) * *extrasCapac);
|
|
||||||
if (!*extras) {
|
|
||||||
_xopt_set_err(ctx, err, "could not realloc arguments array");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _xopt_get_size(const char *arg) {
|
|
||||||
int size;
|
|
||||||
for (size = 0; size < 2; size++) {
|
|
||||||
if (arg[size] != '-') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _xopt_get_arg(const xoptContext *ctx, const char *arg, size_t len,
|
|
||||||
int size, const xoptOption **option, size_t *option_index) {
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
*option = 0;
|
|
||||||
|
|
||||||
/* find the argument */
|
|
||||||
for (i = 0; i < ctx->options_count; i++) {
|
|
||||||
const xoptOption *opt = &ctx->options[i];
|
|
||||||
|
|
||||||
if ((size == 1 && opt->shortArg == arg[0])
|
|
||||||
|| (opt->longArg && strlen(opt->longArg) == len && !strncmp(opt->longArg, arg, len))) {
|
|
||||||
*option_index = i;
|
|
||||||
*option = opt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* determine the optionality of a value */
|
|
||||||
if (!*option || (*option)->options & XOPT_TYPE_BOOL) {
|
|
||||||
return 0;
|
|
||||||
} else if ((*option)->options & XOPT_PARAM_OPTIONAL) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _xopt_set(xoptContext *ctx, void *data, const xoptOption *option, const char *val,
|
|
||||||
bool longArg, const char **err) {
|
|
||||||
/* determine callback */
|
|
||||||
xoptCallback callback = option->callback ? option->callback : &_xopt_default_callback;
|
|
||||||
|
|
||||||
/* dispatch callback */
|
|
||||||
callback(val, data, option, longArg, err);
|
|
||||||
|
|
||||||
/* we check err here instead of relying upon longjmp()
|
|
||||||
since we can't call _set_err() with a context */
|
|
||||||
if (*err) {
|
|
||||||
assert(ctx->jmp != NULL);
|
|
||||||
longjmp(*ctx->jmp, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _xopt_default_callback(const char *value, void *data,
|
|
||||||
const xoptOption *option, bool longArg, const char **err) {
|
|
||||||
void *target;
|
|
||||||
char *parsePtr = 0;
|
|
||||||
|
|
||||||
/* is a value specified? */
|
|
||||||
if ((!value || !strlen(value)) && !(option->options & XOPT_TYPE_BOOL)) {
|
|
||||||
/* we reach this point when they specified an optional, non-boolean
|
|
||||||
option but didn't specify a custom handler (therefore, it's not
|
|
||||||
optional).
|
|
||||||
|
|
||||||
to fix, just remove the optional flag or specify a callback to handle
|
|
||||||
it yourself.
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get location */
|
|
||||||
target = ((char*) data) + option->offset;
|
|
||||||
|
|
||||||
/* switch on the type */
|
|
||||||
switch (option->options & 0x3F) {
|
|
||||||
case XOPT_TYPE_BOOL:
|
|
||||||
/* booleans are special in that they won't have an argument passed
|
|
||||||
into this callback */
|
|
||||||
*((_Bool*) target) = true;
|
|
||||||
break;
|
|
||||||
case XOPT_TYPE_STRING:
|
|
||||||
/* lifetime here works out fine; argv can usually be assumed static-like
|
|
||||||
in nature */
|
|
||||||
*((const char**) target) = value;
|
|
||||||
break;
|
|
||||||
case XOPT_TYPE_INT:
|
|
||||||
*((int*) target) = (int) strtol(value, &parsePtr, 0);
|
|
||||||
break;
|
|
||||||
case XOPT_TYPE_LONG:
|
|
||||||
*((long*) target) = strtol(value, &parsePtr, 0);
|
|
||||||
break;
|
|
||||||
case XOPT_TYPE_FLOAT:
|
|
||||||
*((float*) target) = (float) strtod(value, &parsePtr);
|
|
||||||
break;
|
|
||||||
case XOPT_TYPE_DOUBLE:
|
|
||||||
*((double*) target) = strtod(value, &parsePtr);
|
|
||||||
break;
|
|
||||||
default: /* something wonky, or the implementation specifies two types */
|
|
||||||
fprintf(stderr, "warning: XOpt argument type invalid: %ld\n",
|
|
||||||
option->options & 0x2F);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check that our parsing functions worked */
|
|
||||||
if (parsePtr && *parsePtr) {
|
|
||||||
if (longArg) {
|
|
||||||
_xopt_set_err(NULL, err, "value isn't a valid number: --%s=%s",
|
|
||||||
(void*) option->longArg, value);
|
|
||||||
} else {
|
|
||||||
_xopt_set_err(NULL, err, "value isn't a valid number: -%c %s",
|
|
||||||
option->shortArg, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
225
deps/xopt/xopt.h
vendored
225
deps/xopt/xopt.h
vendored
@ -1,225 +0,0 @@
|
|||||||
/**
|
|
||||||
* XOpt - command line parsing library
|
|
||||||
*
|
|
||||||
* Copyright (c) 2015 Josh Junon.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* 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 OR COPYRIGHT HOLDERS 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.
|
|
||||||
*/
|
|
||||||
#ifndef XOPT_H__
|
|
||||||
#define XOPT_H__
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
struct xoptOption;
|
|
||||||
|
|
||||||
#ifndef offsetof
|
|
||||||
# define offsetof(T, member) (size_t)(&(((T*)0)->member))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback type for handling values.
|
|
||||||
* Called when a command line argument has been
|
|
||||||
* processed.
|
|
||||||
*/
|
|
||||||
typedef void (*xoptCallback)(
|
|
||||||
const char *value, /* string cmd line option */
|
|
||||||
void *data, /* custom data structure */
|
|
||||||
const struct xoptOption *option, /* detected option */
|
|
||||||
bool longArg, /* true if the long-arg version
|
|
||||||
was used */
|
|
||||||
const char **err); /* err output */
|
|
||||||
|
|
||||||
enum xoptOptionFlag {
|
|
||||||
XOPT_TYPE_STRING = 0x1, /* const char* type */
|
|
||||||
XOPT_TYPE_INT = 0x2, /* int type */
|
|
||||||
XOPT_TYPE_LONG = 0x4, /* long type */
|
|
||||||
XOPT_TYPE_FLOAT = 0x8, /* float type */
|
|
||||||
XOPT_TYPE_DOUBLE = 0x10, /* double type */
|
|
||||||
XOPT_TYPE_BOOL = 0x20, /* boolean (int) type */
|
|
||||||
|
|
||||||
XOPT_PARAM_OPTIONAL = 0x40, /* whether the argument value is
|
|
||||||
optional */
|
|
||||||
XOPT_REQUIRED = 0x80 /* indicates the flag must be
|
|
||||||
present on the command line */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum xoptContextFlag {
|
|
||||||
XOPT_CTX_KEEPFIRST = 0x1, /* don't ignore argv[0] */
|
|
||||||
XOPT_CTX_POSIXMEHARDER = 0x2, /* options cannot come after
|
|
||||||
extra arguments */
|
|
||||||
XOPT_CTX_NOCONDENSE = 0x4, /* don't allow short args to be
|
|
||||||
condensed (i.e. `ls -laF') */
|
|
||||||
XOPT_CTX_SLOPPYSHORTS = 0x8, /* allow short arg values to be
|
|
||||||
directly after the character */
|
|
||||||
XOPT_CTX_STRICT = 0x10 /* fails on invalid arguments */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct xoptOption {
|
|
||||||
const char *longArg; /* --long-arg-name, or 0 for short
|
|
||||||
arg only */
|
|
||||||
const char shortArg; /* -s hort arg character, or '\0'
|
|
||||||
for long arg only */
|
|
||||||
size_t offset; /* offsetof(type, property) for
|
|
||||||
automatic configuration handler */
|
|
||||||
xoptCallback callback; /* callback for resolved option
|
|
||||||
handling */
|
|
||||||
long options; /* xoptOptionFlag options */
|
|
||||||
const char *argDescrip; /* --argument=argDescrip (autohelp) */
|
|
||||||
const char *descrip; /* argument explanation (autohelp) */
|
|
||||||
} xoptOption;
|
|
||||||
|
|
||||||
/* option list terminator */
|
|
||||||
#define XOPT_NULLOPTION {0, 0, 0, 0, 0, 0, 0}
|
|
||||||
|
|
||||||
typedef struct xoptContext xoptContext;
|
|
||||||
|
|
||||||
typedef struct xoptAutohelpOptions {
|
|
||||||
const char *usage; /* usage string, or null */
|
|
||||||
const char *prefix; /* printed before options, or null */
|
|
||||||
const char *suffix; /* printed after options, or null */
|
|
||||||
size_t spacer; /* number of spaces between option and
|
|
||||||
description */
|
|
||||||
} xoptAutohelpOptions;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an XOpt context to be used with
|
|
||||||
* subsequent calls to XOpt functions
|
|
||||||
*/
|
|
||||||
xoptContext*
|
|
||||||
xopt_context(
|
|
||||||
const char *name, /* name of the argument set (usually
|
|
||||||
name of the cli binary file/cmd */
|
|
||||||
const xoptOption *options, /* list of xoptOption objects,
|
|
||||||
terminated with XOPT_NULLOPTION */
|
|
||||||
long flags, /* xoptContextFlag flags */
|
|
||||||
const char **err); /* pointer to a const char* that
|
|
||||||
receives an err should one occur -
|
|
||||||
set to 0 if command completed
|
|
||||||
successfully */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the command line of a program
|
|
||||||
* and returns the number of non-options
|
|
||||||
* returned to the `extras' pointer (see
|
|
||||||
* below)
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
xopt_parse(
|
|
||||||
xoptContext *ctx, /* previously created XOpt context */
|
|
||||||
int argc, /* argc, from int main() */
|
|
||||||
const char **argv, /* argv, from int main() */
|
|
||||||
void *data, /* a custom data object whos type
|
|
||||||
corresponds to `.offset' values
|
|
||||||
specified in the options list;
|
|
||||||
populated with values interpreted
|
|
||||||
from the command line */
|
|
||||||
const char ***extras, /* receives a list of extra non-option
|
|
||||||
arguments (i.e. files, subcommands,
|
|
||||||
etc.) - length of which is returned
|
|
||||||
by the function call */
|
|
||||||
const char **err); /* pointer to a const char* that
|
|
||||||
receives an err should one occur -
|
|
||||||
set to 0 if command completed
|
|
||||||
successfully */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates and prints a help message
|
|
||||||
* and prints it to a FILE stream.
|
|
||||||
* If `defaults' is supplied, uses
|
|
||||||
* offsets (values) defined by the options
|
|
||||||
* list to show default options
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
xopt_autohelp(
|
|
||||||
xoptContext *ctx, /* previously created XOpt context */
|
|
||||||
FILE *stream, /* a stream to print to - if 0,
|
|
||||||
defaults to `stderr'. */
|
|
||||||
const xoptAutohelpOptions *options, /* configuration options to tailor
|
|
||||||
autohelp output */
|
|
||||||
const char **err); /* pointer to a const char* that
|
|
||||||
receives an err should one occur -
|
|
||||||
set to 0 if command completed
|
|
||||||
successfully */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a default option parser that's sane for most cases.
|
|
||||||
*
|
|
||||||
* Assumes there's a `help` property that is boolean-checkable that exists on the
|
|
||||||
* config pointer passed to `config_ptr` (i.e. does a lookup of `config_ptr->help`).
|
|
||||||
*
|
|
||||||
* In the event help is invoked, xopt will `goto xopt_help`. It is up to you to define such
|
|
||||||
* a label in order to recover. In this case, extrav will still be allocated and will still need to be
|
|
||||||
* freed.
|
|
||||||
*
|
|
||||||
* To be extra clear, you need to free `extrav_ptr` is if `*err_ptr` is not `NULL`.
|
|
||||||
*
|
|
||||||
* `name` is the name of the binary you'd like to pass to the context (welcome to use `argv[0]` here),
|
|
||||||
* `options` is a reference to the xoptOptions array you've specified,
|
|
||||||
* `config_ptr` is a *pointer* to your configuration instance,
|
|
||||||
* `argc` and `argv` are the int/const char ** passed into main,
|
|
||||||
* `extrac_ptr` and `extrav_ptr` are pointers to an `int`/`const char **`
|
|
||||||
* (so `int*` and `const char ***`, respectively) that receive the parsed extra args
|
|
||||||
* (note that, unless there is an error, `extrav_ptr` is owned by your program and must
|
|
||||||
* be `free()`'d when you're done using it, even if there are zero extra arguments),
|
|
||||||
* and `err_ptr` is a pointer to a `const char *` (so a `const char **`) that receives any error
|
|
||||||
* strings in the event of a problem. These errors are statically allocated so no need to
|
|
||||||
* free them. This variable should be initialized to NULL and checked after calling
|
|
||||||
* `XOPT_SIMPLE_PARSE()`.
|
|
||||||
*
|
|
||||||
* `autohelp_file`, `autohelp_usage`, `autohelp_prefix`, `autohelp_suffix` and `autohelp_spacer` are all
|
|
||||||
* parameters to the `xoptAutohelpOptions` struct (with the exception of `autohelp_file`, which must be a
|
|
||||||
* `FILE*` reference (e.g. `stdout` or `stderr`) which receives the rendered autohelp text). Consult the
|
|
||||||
* `xoptAutohelpOptions` struct above for documentation as to valid values for each of these properties.
|
|
||||||
*/
|
|
||||||
#define XOPT_SIMPLE_PARSE(name, flags, options, config_ptr, argc, argv, extrac_ptr, extrav_ptr, err_ptr, autohelp_file, autohelp_usage, autohelp_prefix, autohelp_suffix, autohelp_spacer) do { \
|
|
||||||
xoptContext *_xopt_ctx; \
|
|
||||||
*(err_ptr) = NULL; \
|
|
||||||
_xopt_ctx = xopt_context((name), (options), ((flags) ^ XOPT_CTX_POSIXMEHARDER ^ XOPT_CTX_STRICT), (err_ptr)); \
|
|
||||||
if (*(err_ptr)) break; \
|
|
||||||
*extrac_ptr = xopt_parse(_xopt_ctx, (argc), (argv), (config_ptr), (extrav_ptr), (err_ptr)); \
|
|
||||||
if ((config_ptr)->help) { \
|
|
||||||
xoptAutohelpOptions __xopt_autohelp_opts; \
|
|
||||||
__xopt_autohelp_opts.usage = (autohelp_usage); \
|
|
||||||
__xopt_autohelp_opts.prefix = (autohelp_prefix); \
|
|
||||||
__xopt_autohelp_opts.suffix = (autohelp_suffix); \
|
|
||||||
__xopt_autohelp_opts.spacer = (autohelp_spacer); \
|
|
||||||
xopt_autohelp(_xopt_ctx, (autohelp_file), &__xopt_autohelp_opts, (err_ptr)); \
|
|
||||||
if (*(err_ptr)) goto __xopt_end_free_extrav; \
|
|
||||||
goto xopt_help; \
|
|
||||||
} \
|
|
||||||
if (*(err_ptr)) goto __xopt_end_free_ctx; \
|
|
||||||
__xopt_end_free_ctx: \
|
|
||||||
free(_xopt_ctx); \
|
|
||||||
break; \
|
|
||||||
__xopt_end_free_extrav: \
|
|
||||||
free(*(extrav_ptr)); \
|
|
||||||
free(_xopt_ctx); \
|
|
||||||
break; \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
487
src/main.c
487
src/main.c
@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
#include "backtrace.h"
|
#include "backtrace.h"
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
#include "xopt.h"
|
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -41,47 +41,13 @@ struct backtrace_state* g_backtrace_state;
|
|||||||
|
|
||||||
const char* k_db_path_default = "db.sqlite";
|
const char* k_db_path_default = "db.sqlite";
|
||||||
|
|
||||||
#define XOPT_PARSE( \
|
|
||||||
name, flags, options, config_ptr, argc, argv, extrac_ptr, extrav_ptr, err_ptr, autohelp_file, autohelp_usage, autohelp_prefix, autohelp_suffix, autohelp_spacer) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
xoptContext* _xopt_ctx; \
|
|
||||||
*(err_ptr) = NULL; \
|
|
||||||
_xopt_ctx = xopt_context((name), (options), ((flags) ^ XOPT_CTX_POSIXMEHARDER), (err_ptr)); \
|
|
||||||
if (*(err_ptr)) \
|
|
||||||
break; \
|
|
||||||
*extrac_ptr = xopt_parse(_xopt_ctx, (argc), (argv), (config_ptr), (extrav_ptr), (err_ptr)); \
|
|
||||||
if ((config_ptr)->help) \
|
|
||||||
{ \
|
|
||||||
xoptAutohelpOptions __xopt_autohelp_opts; \
|
|
||||||
__xopt_autohelp_opts.usage = (autohelp_usage); \
|
|
||||||
__xopt_autohelp_opts.prefix = (autohelp_prefix); \
|
|
||||||
__xopt_autohelp_opts.suffix = (autohelp_suffix); \
|
|
||||||
__xopt_autohelp_opts.spacer = (autohelp_spacer); \
|
|
||||||
xopt_autohelp(_xopt_ctx, (autohelp_file), &__xopt_autohelp_opts, (err_ptr)); \
|
|
||||||
if (*(err_ptr)) \
|
|
||||||
goto __xopt_end_free_extrav; \
|
|
||||||
free(_xopt_ctx); \
|
|
||||||
goto xopt_help; \
|
|
||||||
} \
|
|
||||||
if (*(err_ptr)) \
|
|
||||||
goto __xopt_end_free_ctx; \
|
|
||||||
__xopt_end_free_ctx: \
|
|
||||||
free(_xopt_ctx); \
|
|
||||||
break; \
|
|
||||||
__xopt_end_free_extrav: \
|
|
||||||
free(*(extrav_ptr)); \
|
|
||||||
free(_xopt_ctx); \
|
|
||||||
break; \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#if !TARGET_OS_IPHONE && !defined(__ANDROID__)
|
#if !TARGET_OS_IPHONE && !defined(__ANDROID__)
|
||||||
static int _tf_command_test(const char* file, int argc, char* argv[]);
|
static int _tf_command_test(const char* file, int argc, char* argv[]);
|
||||||
static int _tf_command_import(const char* file, int argc, char* argv[]);
|
static int _tf_command_import(const char* file, int argc, char* argv[]);
|
||||||
static int _tf_command_export(const char* file, int argc, char* argv[]);
|
static int _tf_command_export(const char* file, int argc, char* argv[]);
|
||||||
static int _tf_command_run(const char* file, int argc, char* argv[]);
|
static int _tf_command_run(const char* file, int argc, char* argv[]);
|
||||||
static int _tf_command_sandbox(const char* file, int argc, char* argv[]);
|
static int _tf_command_sandbox(const char* file, int argc, char* argv[]);
|
||||||
static int _tf_command_usage(const char* file, int argc, char* argv[]);
|
static int _tf_command_usage(const char* file);
|
||||||
|
|
||||||
typedef struct _command_t
|
typedef struct _command_t
|
||||||
{
|
{
|
||||||
@ -101,140 +67,182 @@ const command_t k_commands[] = {
|
|||||||
static int _tf_command_test(const char* file, int argc, char* argv[])
|
static int _tf_command_test(const char* file, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
#if !defined(__ANDROID__)
|
#if !defined(__ANDROID__)
|
||||||
typedef struct args_t
|
tf_test_options_t test_options =
|
||||||
{
|
{
|
||||||
const char* tests;
|
|
||||||
bool help;
|
|
||||||
} args_t;
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
|
||||||
{ "tests", 't', offsetof(args_t, tests), NULL, XOPT_TYPE_STRING, NULL, "Comma-separated list of test names to run." },
|
|
||||||
{ "help", 'h', offsetof(args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." },
|
|
||||||
XOPT_NULLOPTION,
|
|
||||||
};
|
|
||||||
|
|
||||||
args_t args = { 0 };
|
|
||||||
const char** extras = NULL;
|
|
||||||
int extra_count = 0;
|
|
||||||
const char* err = NULL;
|
|
||||||
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "test [options]", "options:", NULL, 15);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
tf_test_options_t test_options = {
|
|
||||||
.exe_path = file,
|
.exe_path = file,
|
||||||
.tests = args.tests,
|
|
||||||
};
|
};
|
||||||
|
bool show_usage = false;
|
||||||
|
|
||||||
|
while (!show_usage)
|
||||||
|
{
|
||||||
|
static struct option k_options[] =
|
||||||
|
{
|
||||||
|
{ "tests", required_argument, NULL, 't' },
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
int c = getopt_long(argc, argv, "t:h", k_options, NULL);
|
||||||
|
if (c == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '?':
|
||||||
|
case 'h':
|
||||||
|
default:
|
||||||
|
show_usage = true;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
test_options.tests = optarg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = optind; i < argc; i++)
|
||||||
|
{
|
||||||
|
tf_printf("Unexpected argument: %s\n", argv[i]);
|
||||||
|
show_usage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_usage)
|
||||||
|
{
|
||||||
|
tf_printf("\n%s test [options]\n\n", file);
|
||||||
|
tf_printf("options\n");
|
||||||
|
tf_printf(" -t, --tests tests Comma-separated list of tests to run. (default: all)\n");
|
||||||
|
tf_printf(" -h, --help Show this usage information.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
tf_tests(&test_options);
|
tf_tests(&test_options);
|
||||||
if (extras)
|
return EXIT_SUCCESS;
|
||||||
{
|
#else
|
||||||
free((void*)extras);
|
return EXIT_FAILURE;
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
xopt_help:
|
|
||||||
if (extras)
|
|
||||||
{
|
|
||||||
free((void*)extras);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _tf_command_import(const char* file, int argc, char* argv[])
|
static int _tf_command_import(const char* file, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
typedef struct args_t
|
const char* user = "import";
|
||||||
{
|
const char* db_path = k_db_path_default;
|
||||||
const char* user;
|
bool show_usage = false;
|
||||||
const char* db_path;
|
|
||||||
bool help;
|
|
||||||
} args_t;
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
while (!show_usage)
|
||||||
{ "user", 'u', offsetof(args_t, user), NULL, XOPT_TYPE_STRING, NULL, "User into whose account apps will be imported (default: \"import\")." },
|
|
||||||
{ "db-path", 'd', offsetof(args_t, db_path), NULL, XOPT_TYPE_STRING, NULL, "Sqlite database path (default: db.sqlite)." },
|
|
||||||
{ "help", 'h', offsetof(args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." },
|
|
||||||
XOPT_NULLOPTION,
|
|
||||||
};
|
|
||||||
|
|
||||||
args_t args = { .user = "import", .db_path = k_db_path_default };
|
|
||||||
const char** extras = NULL;
|
|
||||||
int extra_count = 0;
|
|
||||||
const char* err = NULL;
|
|
||||||
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr,
|
|
||||||
"import [options] [paths] ...", "options:", NULL, 15);
|
|
||||||
if (err)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
static struct option k_options[] =
|
||||||
return 2;
|
{
|
||||||
|
{ "user", required_argument, NULL, 'u' },
|
||||||
|
{ "db-path", required_argument, NULL, 'd' },
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
int c = getopt_long(argc, argv, "u:d:h", k_options, NULL);
|
||||||
|
if (c == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '?':
|
||||||
|
case 'h':
|
||||||
|
default:
|
||||||
|
show_usage = true;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
user = optarg;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
db_path = optarg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, args.db_path);
|
if (show_usage)
|
||||||
if (extra_count)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < extra_count; i++)
|
tf_printf("\n%s import [options] [paths...]\n\n", file);
|
||||||
|
tf_printf("options:\n");
|
||||||
|
tf_printf(" -u, --user user User into whose account apps will be imported (default: \"import\").\n");
|
||||||
|
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", k_db_path_default);
|
||||||
|
tf_printf(" -h, --help Show this usage information.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path);
|
||||||
|
if (optind < argc)
|
||||||
|
{
|
||||||
|
for (int i = optind; i < argc; i++)
|
||||||
{
|
{
|
||||||
tf_printf("Importing %s...\n", extras[i]);
|
tf_printf("Importing %s...\n", argv[i]);
|
||||||
tf_ssb_import(ssb, args.user, extras[i]);
|
tf_ssb_import(ssb, user, argv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tf_printf("Importing %s...\n", "apps");
|
tf_printf("Importing %s...\n", "apps");
|
||||||
tf_ssb_import(ssb, args.user, "apps");
|
tf_ssb_import(ssb, user, "apps");
|
||||||
}
|
}
|
||||||
tf_ssb_destroy(ssb);
|
tf_ssb_destroy(ssb);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
if (extras)
|
|
||||||
{
|
|
||||||
free((void*)extras);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
xopt_help:
|
|
||||||
if (extras)
|
|
||||||
{
|
|
||||||
free((void*)extras);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _tf_command_export(const char* file, int argc, char* argv[])
|
static int _tf_command_export(const char* file, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
typedef struct args_t
|
const char* user = "core";
|
||||||
{
|
const char* db_path = k_db_path_default;
|
||||||
const char* user;
|
bool show_usage = false;
|
||||||
const char* db_path;
|
|
||||||
bool help;
|
|
||||||
} args_t;
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
while (!show_usage)
|
||||||
{ "db-path", 'd', offsetof(args_t, db_path), NULL, XOPT_TYPE_STRING, NULL, "Sqlite database path (default: db.sqlite)." },
|
|
||||||
{ "user", 'u', offsetof(args_t, user), NULL, XOPT_TYPE_STRING, NULL, "User into whose apps will be exported (default: \"core\")." },
|
|
||||||
{ "help", 'h', offsetof(args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." },
|
|
||||||
XOPT_NULLOPTION,
|
|
||||||
};
|
|
||||||
|
|
||||||
args_t args = { .user = "core", .db_path = k_db_path_default };
|
|
||||||
const char** extras = NULL;
|
|
||||||
int extra_count = 0;
|
|
||||||
const char* err = NULL;
|
|
||||||
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr,
|
|
||||||
"export [options] [paths] ...", "options:", NULL, 15);
|
|
||||||
if (err)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
static const struct option k_options[] =
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, args.db_path);
|
|
||||||
if (extra_count)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < extra_count; i++)
|
|
||||||
{
|
{
|
||||||
tf_printf("Exporting %s...\n", extras[i]);
|
{ "user", required_argument, NULL, 'u' },
|
||||||
tf_ssb_export(ssb, extras[i]);
|
{ "db-path", required_argument, NULL, 'd' },
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
int c = getopt_long(argc, argv, "u:d:h", k_options, NULL);
|
||||||
|
if (c == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '?':
|
||||||
|
case 'h':
|
||||||
|
default:
|
||||||
|
show_usage = true;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
user = optarg;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
db_path = optarg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_usage)
|
||||||
|
{
|
||||||
|
tf_printf("\n%s export [options] [paths...]\n\n", file);
|
||||||
|
tf_printf("options:\n");
|
||||||
|
tf_printf(" -u, --user user User from whose account apps will be exported (default: \"core\").\n");
|
||||||
|
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", k_db_path_default);
|
||||||
|
tf_printf(" -h, --help Show this usage information.\n");
|
||||||
|
tf_printf("\n");
|
||||||
|
tf_printf("paths Paths of apps to export (example: /~core/ssb /~user/app).\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path);
|
||||||
|
if (optind < argc)
|
||||||
|
{
|
||||||
|
for (int i = optind; i < argc; i++)
|
||||||
|
{
|
||||||
|
tf_printf("Exporting %s...\n", argv[i]);
|
||||||
|
tf_ssb_export(ssb, argv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -253,25 +261,13 @@ static int _tf_command_export(const char* file, int argc, char* argv[])
|
|||||||
for (int i = 0; i < (int)_countof(k_export); i++)
|
for (int i = 0; i < (int)_countof(k_export); i++)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
snprintf(buffer, sizeof(buffer), "/~%s/%s", args.user, k_export[i]);
|
snprintf(buffer, sizeof(buffer), "/~%s/%s", user, k_export[i]);
|
||||||
tf_printf("Exporting %s...\n", buffer);
|
tf_printf("Exporting %s...\n", buffer);
|
||||||
tf_ssb_export(ssb, buffer);
|
tf_ssb_export(ssb, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tf_ssb_destroy(ssb);
|
tf_ssb_destroy(ssb);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
if (extras)
|
|
||||||
{
|
|
||||||
free((void*)extras);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
xopt_help:
|
|
||||||
if (extras)
|
|
||||||
{
|
|
||||||
free((void*)extras);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -412,21 +408,6 @@ static void _shed_privileges()
|
|||||||
|
|
||||||
static int _tf_command_run(const char* file, int argc, char* argv[])
|
static int _tf_command_run(const char* file, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
xoptOption options[] = {
|
|
||||||
{ "script", 's', offsetof(tf_run_args_t, script), NULL, XOPT_TYPE_STRING, NULL, "Script to run (default: core/core.js)." },
|
|
||||||
{ "ssb-port", 'b', offsetof(tf_run_args_t, ssb_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run SSB (default: 8008)." },
|
|
||||||
{ "http-port", 'p', offsetof(tf_run_args_t, http_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run Tilde Friends web server (default: 12345)." },
|
|
||||||
{ "https-port", 'q', offsetof(tf_run_args_t, https_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run secure Tilde Friends web server (default: 12346)." },
|
|
||||||
{ "db-path", 'd', offsetof(tf_run_args_t, db_path), NULL, XOPT_TYPE_STRING, NULL, "Sqlite database path (default: db.sqlite)." },
|
|
||||||
{ "count", 'n', offsetof(tf_run_args_t, count), NULL, XOPT_TYPE_INT, NULL, "Number of instances to run." },
|
|
||||||
{ "args", 'a', offsetof(tf_run_args_t, args), NULL, XOPT_TYPE_STRING, NULL, "Arguments of the form key=value,foo=bar,verbose=true." },
|
|
||||||
{ "one-proc", 'o', offsetof(tf_run_args_t, one_proc), NULL, XOPT_TYPE_BOOL, NULL, "Run everything in one process (unsafely!)." },
|
|
||||||
{ "zip", 'z', offsetof(tf_run_args_t, zip), NULL, XOPT_TYPE_STRING, NULL, "Zip archive from which to load files." },
|
|
||||||
{ "verbose", 'v', offsetof(tf_run_args_t, verbose), NULL, XOPT_TYPE_BOOL, NULL, "Log raw messages." },
|
|
||||||
{ "help", 'h', offsetof(tf_run_args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." },
|
|
||||||
XOPT_NULLOPTION,
|
|
||||||
};
|
|
||||||
|
|
||||||
tf_run_args_t args = {
|
tf_run_args_t args = {
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.script = "core/core.js",
|
.script = "core/core.js",
|
||||||
@ -435,16 +416,86 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
|
|||||||
.ssb_port = 8008,
|
.ssb_port = 8008,
|
||||||
.db_path = k_db_path_default,
|
.db_path = k_db_path_default,
|
||||||
};
|
};
|
||||||
const char** extras = NULL;
|
bool show_usage = false;
|
||||||
int extra_count = 0;
|
|
||||||
const char* err = NULL;
|
|
||||||
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr,
|
|
||||||
"run [options] [paths] ...", "options:", NULL, 15);
|
|
||||||
|
|
||||||
if (err)
|
while (!show_usage)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
static const struct option k_options[] =
|
||||||
return 2;
|
{
|
||||||
|
{ "script", required_argument, NULL, 's' },
|
||||||
|
{ "ssb-port", required_argument, NULL, 'b' },
|
||||||
|
{ "http-port", required_argument, NULL, 'p' },
|
||||||
|
{ "https-port", required_argument, NULL, 'q' },
|
||||||
|
{ "db-path", required_argument, NULL, 'd' },
|
||||||
|
{ "count", required_argument, NULL, 'n' },
|
||||||
|
{ "args", required_argument, NULL, 'a' },
|
||||||
|
{ "one-proc", no_argument, NULL, 'o' },
|
||||||
|
{ "zip", required_argument, NULL, 'z' },
|
||||||
|
{ "verbose", no_argument, NULL, 'v' },
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
};
|
||||||
|
int c = getopt_long(argc, argv, "s:b:p:q:d:n:a:oz:vh", k_options, NULL);
|
||||||
|
if (c == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '?':
|
||||||
|
case 'h':
|
||||||
|
default:
|
||||||
|
show_usage = true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
args.script = optarg;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
args.ssb_port = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
args.http_port = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
args.https_port = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
args.db_path = optarg;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
args.count = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
args.args = optarg;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
args.one_proc = true;
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
args.zip = optarg;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
args.verbose = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_usage)
|
||||||
|
{
|
||||||
|
tf_printf("\n%s run [options]\n\n", file);
|
||||||
|
tf_printf("options\n");
|
||||||
|
tf_printf(" -s, --script script Script to run (default: core/core.js).\n");
|
||||||
|
tf_printf(" -b, --ssb-port port Port on which to run SSB (default: 8008, 0 disables).\n");
|
||||||
|
tf_printf(" -p, --http-port port Port on which to run Tilde Friends web server (default: 12345).\n");
|
||||||
|
tf_printf(" -q, --https-port port Port on which to run secure Tilde Friends web server (default: 12346).\n");
|
||||||
|
tf_printf(" -d, --db-path path SQLite database path (default: %s).\n", k_db_path_default);
|
||||||
|
tf_printf(" -n, --count count Number of instances to run.\n");
|
||||||
|
tf_printf(" -a, --args args Arguments of the format key=value,foo=bar,verbose=true.\n");
|
||||||
|
tf_printf(" -o, --one-proc Run everything in one process (unsafely!).\n");
|
||||||
|
tf_printf(" -z, --zip path Zip archive from which to load files.\n");
|
||||||
|
tf_printf(" -v, --verbose Log raw messages.\n");
|
||||||
|
tf_printf(" -h, --help Show this usage information.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
@ -479,44 +530,41 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
|
|||||||
tf_free(data);
|
tf_free(data);
|
||||||
tf_free(threads);
|
tf_free(threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extras)
|
|
||||||
{
|
|
||||||
free((void*)extras);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
xopt_help:
|
|
||||||
if (extras)
|
|
||||||
{
|
|
||||||
free((void*)extras);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
typedef struct args_t
|
bool show_usage = false;
|
||||||
{
|
|
||||||
const char* script;
|
|
||||||
bool help;
|
|
||||||
} args_t;
|
|
||||||
|
|
||||||
xoptOption options[] = {
|
while (!show_usage)
|
||||||
{ "help", 'h', offsetof(args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." },
|
|
||||||
XOPT_NULLOPTION,
|
|
||||||
};
|
|
||||||
|
|
||||||
args_t args = { 0 };
|
|
||||||
const char** extras = NULL;
|
|
||||||
int extra_count = 0;
|
|
||||||
const char* err = NULL;
|
|
||||||
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr,
|
|
||||||
"sandbox [options]", "options:", NULL, 15);
|
|
||||||
if (err)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
static const struct option k_options[] =
|
||||||
return 2;
|
{
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
int c = getopt_long(argc, argv, "h", k_options, NULL);
|
||||||
|
if (c == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '?':
|
||||||
|
case 'h':
|
||||||
|
default:
|
||||||
|
show_usage = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_usage)
|
||||||
|
{
|
||||||
|
tf_printf("\nUsage: %s sandbox [options]\n\n", file);
|
||||||
|
tf_printf("options:\n");
|
||||||
|
tf_printf(" -h, --help Show this usage information.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
@ -528,22 +576,11 @@ static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
|||||||
/* The caller will trigger tf_task_activate with a message. */
|
/* The caller will trigger tf_task_activate with a message. */
|
||||||
tf_task_run(task);
|
tf_task_run(task);
|
||||||
tf_task_destroy(task);
|
tf_task_destroy(task);
|
||||||
if (extras)
|
return EXIT_SUCCESS;
|
||||||
{
|
|
||||||
free((void*)extras);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
xopt_help:
|
|
||||||
if (extras)
|
|
||||||
{
|
|
||||||
free((void*)extras);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(__ANDROID__)
|
#if !defined(__ANDROID__)
|
||||||
static int _tf_command_usage(const char* file, int argc, char* argv[])
|
static int _tf_command_usage(const char* file)
|
||||||
{
|
{
|
||||||
tf_printf("Usage: %s command [command-options]\n", file);
|
tf_printf("Usage: %s command [command-options]\n", file);
|
||||||
tf_printf("commands:\n");
|
tf_printf("commands:\n");
|
||||||
@ -675,15 +712,15 @@ int main(int argc, char* argv[])
|
|||||||
const command_t* command = &k_commands[i];
|
const command_t* command = &k_commands[i];
|
||||||
if (strcmp(argv[1], command->name) == 0)
|
if (strcmp(argv[1], command->name) == 0)
|
||||||
{
|
{
|
||||||
result = command->callback(argv[0], argc - 2, argv + 2);
|
result = command->callback(argv[0], argc - 1, argv + 1);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = _tf_command_usage(argv[0], argc, argv);
|
result = _tf_command_usage(argv[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = _tf_command_run(argv[0], argc - 1, argv + 1);
|
result = _tf_command_run(argv[0], argc, argv);
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
tf_mem_shutdown();
|
tf_mem_shutdown();
|
||||||
|
Loading…
Reference in New Issue
Block a user