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:
Cory McWilliams 2024-02-25 14:45:31 -05:00
parent 4cb82d81b7
commit 8c13f5dbba
32 changed files with 263 additions and 4426 deletions

View File

@ -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)

View File

@ -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

View File

@ -1,7 +0,0 @@
version: 2
jobs:
build:
machine: true
steps:
- checkout
- run: docker build -f .circleci/Dockerfile.test .

View File

@ -1 +0,0 @@
.gitignore

View File

@ -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

View File

@ -1,6 +0,0 @@
*.sw[a-p]
/bin/
/build/
/.tup/
/*.o
/*.a

View File

@ -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
View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +0,0 @@
/*-test
/*.o

View File

@ -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]

View File

@ -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;
}

View File

@ -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
View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -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,
};
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)
while (!show_usage)
{
fprintf(stderr, "Error: %s\n", err);
return 2;
static struct option k_options[] =
{
{ "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 (extra_count)
if (show_usage)
{
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_ssb_import(ssb, args.user, extras[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,
};
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)
while (!show_usage)
{
fprintf(stderr, "Error: %s\n", err);
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++)
static const struct option k_options[] =
{
tf_printf("Exporting %s...\n", extras[i]);
tf_ssb_export(ssb, extras[i]);
{ "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;
}
}
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
@ -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,
};
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)
while (!show_usage)
{
fprintf(stderr, "Error: %s\n", err);
return 2;
static const struct option k_options[] =
{
{ "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__)
@ -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();