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/sqlite \
|
||||
-Ideps/valgrind \
|
||||
-Ideps/xopt \
|
||||
-Wdouble-promotion \
|
||||
-Werror
|
||||
ifeq ($(UNAME_M),x86_64)
|
||||
@ -497,18 +496,6 @@ $(SQLITE_OBJS): CFLAGS += \
|
||||
-Wno-unused-function \
|
||||
-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 := \
|
||||
deps/quickjs/cutils.c \
|
||||
deps/quickjs/libbf.c \
|
||||
@ -637,8 +624,7 @@ ALL_APP_OBJS := \
|
||||
$(QUICKJS_OBJS) \
|
||||
$(SODIUM_OBJS) \
|
||||
$(SQLITE_OBJS) \
|
||||
$(UV_OBJS) \
|
||||
$(XOPT_OBJS)
|
||||
$(UV_OBJS)
|
||||
|
||||
DEPS = $(ALL_APP_OBJS:.o=.d)
|
||||
-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
|
477
src/main.c
477
src/main.c
@ -11,8 +11,8 @@
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "sqlite3.h"
|
||||
#include "xopt.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -41,47 +41,13 @@ struct backtrace_state* g_backtrace_state;
|
||||
|
||||
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__)
|
||||
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_export(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_usage(const char* file, int argc, char* argv[]);
|
||||
static int _tf_command_usage(const char* file);
|
||||
|
||||
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[])
|
||||
{
|
||||
#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,
|
||||
.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);
|
||||
if (extras)
|
||||
{
|
||||
free((void*)extras);
|
||||
}
|
||||
return 0;
|
||||
xopt_help:
|
||||
if (extras)
|
||||
{
|
||||
free((void*)extras);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
#else
|
||||
return EXIT_FAILURE;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _tf_command_import(const char* file, int argc, char* argv[])
|
||||
{
|
||||
typedef struct args_t
|
||||
{
|
||||
const char* user;
|
||||
const char* db_path;
|
||||
bool help;
|
||||
} args_t;
|
||||
const char* user = "import";
|
||||
const char* db_path = k_db_path_default;
|
||||
bool show_usage = false;
|
||||
|
||||
xoptOption options[] = {
|
||||
{ "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,
|
||||
while (!show_usage)
|
||||
{
|
||||
static struct option k_options[] =
|
||||
{
|
||||
{ "user", required_argument, NULL, 'u' },
|
||||
{ "db-path", required_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
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)
|
||||
int c = getopt_long(argc, argv, "u:d:h", k_options, NULL);
|
||||
if (c == -1)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", err);
|
||||
return 2;
|
||||
break;
|
||||
}
|
||||
|
||||
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, args.db_path);
|
||||
if (extra_count)
|
||||
switch (c)
|
||||
{
|
||||
for (int i = 0; i < extra_count; i++)
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
show_usage = true;
|
||||
break;
|
||||
case 'u':
|
||||
user = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
db_path = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (show_usage)
|
||||
{
|
||||
tf_printf("Importing %s...\n", extras[i]);
|
||||
tf_ssb_import(ssb, args.user, extras[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", argv[i]);
|
||||
tf_ssb_import(ssb, user, argv[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_printf("Importing %s...\n", "apps");
|
||||
tf_ssb_import(ssb, args.user, "apps");
|
||||
tf_ssb_import(ssb, user, "apps");
|
||||
}
|
||||
tf_ssb_destroy(ssb);
|
||||
|
||||
if (extras)
|
||||
{
|
||||
free((void*)extras);
|
||||
}
|
||||
return 0;
|
||||
|
||||
xopt_help:
|
||||
if (extras)
|
||||
{
|
||||
free((void*)extras);
|
||||
}
|
||||
return 1;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int _tf_command_export(const char* file, int argc, char* argv[])
|
||||
{
|
||||
typedef struct args_t
|
||||
{
|
||||
const char* user;
|
||||
const char* db_path;
|
||||
bool help;
|
||||
} args_t;
|
||||
const char* user = "core";
|
||||
const char* db_path = k_db_path_default;
|
||||
bool show_usage = false;
|
||||
|
||||
xoptOption options[] = {
|
||||
{ "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,
|
||||
while (!show_usage)
|
||||
{
|
||||
static const struct option k_options[] =
|
||||
{
|
||||
{ "user", required_argument, NULL, 'u' },
|
||||
{ "db-path", required_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
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)
|
||||
int c = getopt_long(argc, argv, "u:d:h", k_options, NULL);
|
||||
if (c == -1)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", err);
|
||||
return 2;
|
||||
break;
|
||||
}
|
||||
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, args.db_path);
|
||||
if (extra_count)
|
||||
|
||||
switch (c)
|
||||
{
|
||||
for (int i = 0; i < extra_count; i++)
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
show_usage = true;
|
||||
break;
|
||||
case 'u':
|
||||
user = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
db_path = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (show_usage)
|
||||
{
|
||||
tf_printf("Exporting %s...\n", extras[i]);
|
||||
tf_ssb_export(ssb, extras[i]);
|
||||
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
|
||||
@ -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++)
|
||||
{
|
||||
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_ssb_export(ssb, buffer);
|
||||
}
|
||||
}
|
||||
tf_ssb_destroy(ssb);
|
||||
|
||||
if (extras)
|
||||
{
|
||||
free((void*)extras);
|
||||
}
|
||||
return 0;
|
||||
|
||||
xopt_help:
|
||||
if (extras)
|
||||
{
|
||||
free((void*)extras);
|
||||
}
|
||||
return 1;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -412,21 +408,6 @@ static void _shed_privileges()
|
||||
|
||||
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 = {
|
||||
.count = 1,
|
||||
.script = "core/core.js",
|
||||
@ -435,16 +416,86 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
|
||||
.ssb_port = 8008,
|
||||
.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,
|
||||
"run [options] [paths] ...", "options:", NULL, 15);
|
||||
bool show_usage = false;
|
||||
|
||||
if (err)
|
||||
while (!show_usage)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", err);
|
||||
return 2;
|
||||
static const struct option k_options[] =
|
||||
{
|
||||
{ "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;
|
||||
@ -479,44 +530,41 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
|
||||
tf_free(data);
|
||||
tf_free(threads);
|
||||
}
|
||||
|
||||
if (extras)
|
||||
{
|
||||
free((void*)extras);
|
||||
}
|
||||
return result;
|
||||
|
||||
xopt_help:
|
||||
if (extras)
|
||||
{
|
||||
free((void*)extras);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
||||
{
|
||||
typedef struct args_t
|
||||
{
|
||||
const char* script;
|
||||
bool help;
|
||||
} args_t;
|
||||
bool show_usage = false;
|
||||
|
||||
xoptOption options[] = {
|
||||
{ "help", 'h', offsetof(args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." },
|
||||
XOPT_NULLOPTION,
|
||||
while (!show_usage)
|
||||
{
|
||||
static const struct option k_options[] =
|
||||
{
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
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)
|
||||
int c = getopt_long(argc, argv, "h", k_options, NULL);
|
||||
if (c == -1)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", err);
|
||||
return 2;
|
||||
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__)
|
||||
@ -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. */
|
||||
tf_task_run(task);
|
||||
tf_task_destroy(task);
|
||||
if (extras)
|
||||
{
|
||||
free((void*)extras);
|
||||
}
|
||||
return 0;
|
||||
|
||||
xopt_help:
|
||||
if (extras)
|
||||
{
|
||||
free((void*)extras);
|
||||
}
|
||||
return 1;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#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("commands:\n");
|
||||
@ -675,15 +712,15 @@ int main(int argc, char* argv[])
|
||||
const command_t* command = &k_commands[i];
|
||||
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;
|
||||
}
|
||||
}
|
||||
result = _tf_command_usage(argv[0], argc, argv);
|
||||
result = _tf_command_usage(argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = _tf_command_run(argv[0], argc - 1, argv + 1);
|
||||
result = _tf_command_run(argv[0], argc, argv);
|
||||
}
|
||||
done:
|
||||
tf_mem_shutdown();
|
||||
|
Loading…
Reference in New Issue
Block a user