opts_cfg_t* options;
} StreamContext_T;
-static const char* Program_Name = NULL;
-static entry_t* Options = NULL;
-static entry_t* Arguments = NULL;
-
static void opts_parse_short_option( StreamContext_T* ctx );
static void opts_parse_long_option( StreamContext_T* ctx );
static char* opts_parse_optarg(StreamContext_T* ctx, char* opt_name);
static void opts_parse_argument( StreamContext_T* ctx );
static void opts_parse_error(const char* msg, char* opt_name);
-
static opts_cfg_t* opts_get_option_config( opts_cfg_t* opts, OptionType_T typ, char* name );
static char* opts_next_token( StreamContext_T* ctx );
static void opts_consume_ws( StreamContext_T* ctx );
static char opts_next_char( StreamContext_T* ctx );
static char* opts_append_char( char* str, char ch );
static char* strclone(const char* p_old);
-
static void opts_add_option(char* name, char* tag, char* arg);
static void opts_add_argument(char* arg);
-void opts_parse( opts_cfg_t* opts, int argc, char** argv ) {
+static const char* Program_Name = NULL;
+static entry_t* Options = NULL;
+static entry_t* Arguments = NULL;
+static opts_err_cbfn_t Error_Callback = &opts_parse_error;
+
+void opts_parse(opts_cfg_t* opts, opts_err_cbfn_t err_cb, int argc, char** argv) {
/* Setup the stream */
StreamContext_T ctx;
ctx.line_idx = 0;
ctx.options = opts;
(void)opts_next_char( &ctx ); /* Loads up the first char */
+ /* Record the error handler if one was provided */
+ if (NULL != err_cb)
+ Error_Callback = err_cb;
+
/* Record the program name */
Program_Name = argv[0];
opts_parse_short_option( ctx );
opts_add_option( opt_name, config->tag, opt_arg );
} else {
- opts_parse_error("Unknown Option", opt_name);
+ Error_Callback("Unknown Option", opt_name);
}
}
opt_arg = opts_parse_optarg( ctx, opt_name );
opts_add_option( opt_name, config->tag, opt_arg );
} else {
- opts_parse_error("Unknown Option", opt_name);
+ Error_Callback("Unknown Option", opt_name);
}
}
static char* opts_parse_optarg(StreamContext_T* ctx, char* opt_name) {
opts_consume_ws( ctx );
if (('-' == ctx->current) || (EOF == ctx->current))
- opts_parse_error("Expected an argument, none received", opt_name);
+ Error_Callback("Expected an argument, none received", opt_name);
return opts_next_token( ctx );
}
free(buffer);
exit(1);
}
+
longjmp( Exit_Point, code);
}
+
+static void User_Error_Cb(const char* msg, char* opt_name) {
+ (void)msg;
+ (void)opt_name;
+ exit(1);
+}
+
void test_setup(void) {}
//-----------------------------------------------------------------------------
char* args[] = { "prog", (char*)"--foo" };
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
CHECK(opts_is_set("foo", NULL));
}
opts_reset();
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 3, args );
+ opts_parse( Options_Config, NULL, 3, args );
CHECK(opts_is_set("bar", NULL));
CHECK(0 == strcmp("baz", opts_get_value("bar", NULL)));
}
char* args[] = { "prog", (char*)"--bar=baz" };
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
CHECK(opts_is_set("bar", NULL));
CHECK(0 == strcmp("baz", opts_get_value("bar", NULL)));
}
exit_code = setjmp( Exit_Point );
if( 0 == exit_code ) {
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
// If we fail to call exit then this breaks our test
CHECK( false );
} else {
exit_code = setjmp( Exit_Point );
if( 0 == exit_code ) {
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
// If we fail to call exit then this breaks our test
CHECK( false );
} else {
exit_code = setjmp( Exit_Point );
if( 0 == exit_code ) {
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
// If we fail to call exit then this breaks our test
CHECK( false );
} else {
char* args[] = { "prog", (char*)"-a" };
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
CHECK(opts_is_set("a", NULL));
}
opts_reset();
char* args[] = { "prog", (char*)"-ac" };
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
CHECK(opts_is_set("a", NULL));
CHECK(opts_is_set("c", NULL));
}
char* args[] = { "prog", (char*)"-bbaz" };
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
CHECK(opts_is_set("b", NULL));
CHECK(0 == strcmp("baz", opts_get_value("b", NULL)));
}
char* args[] = { "prog", (char*)"-b", "baz" };
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 3, args );
+ opts_parse( Options_Config, NULL, 3, args );
CHECK(opts_is_set("b", NULL));
CHECK(0 == strcmp("baz", opts_get_value("b", NULL)));
}
char* args[] = { "prog", (char*)"-b=baz" };
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
CHECK(opts_is_set("b", NULL));
CHECK(0 == strcmp("baz", opts_get_value("b", NULL)));
}
exit_code = setjmp( Exit_Point );
if( 0 == exit_code ) {
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
// If we fail to call exit then this breaks our test
CHECK( false );
} else {
exit_code = setjmp( Exit_Point );
if( 0 == exit_code ) {
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
// If we fail to call exit then this breaks our test
CHECK( false );
} else {
exit_code = setjmp( Exit_Point );
if( 0 == exit_code ) {
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
// If we fail to call exit then this breaks our test
CHECK( false );
} else {
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 2, args );
+ opts_parse( Options_Config, NULL, 2, args );
const char** args = opts_arguments();
CHECK(0 == strcmp("baz1", args[0]));
CHECK(NULL == args[1]);
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 3, args );
+ opts_parse( Options_Config, NULL, 3, args );
const char** args = opts_arguments();
CHECK(0 == strcmp("baz2", args[0]));
CHECK(0 == strcmp("baz1", args[1]));
opts_reset();
}
+ TEST(Verify_ParseOptions_Calls_the_user_defined_error_handler_if_provided)
+ {
+ int exit_code = 0;
+ char* args[] = { "prog", (char*)"-b" };
+
+ exit_code = setjmp( Exit_Point );
+ if( 0 == exit_code ) {
+ opts_parse( Options_Config, User_Error_Cb, 2, args );
+ // If we fail to call exit then this breaks our test
+ CHECK( false );
+ } else {
+ CHECK( 2 == exit_code );
+ }
+ opts_reset();
+ }
+
TEST(Verify_Select_returns_the_matching_option_by_name)
{
char* args[] = { "prog", "-a", "--foo", "-c" };
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 4, args );
+ opts_parse( Options_Config, NULL, 4, args );
const char** opts = opts_select("c", NULL);
CHECK(0 == strcmp("c", opts[0]));
CHECK(NULL == opts[1]);
char* args[] = { "prog", "-a", "--foo", "-c" };
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 4, args );
+ opts_parse( Options_Config, NULL, 4, args );
const char** opts = opts_select(NULL, "test_c");
CHECK(0 == strcmp("c", opts[0]));
CHECK(NULL == opts[1]);
char* args[] = { "prog", "-a", "--foo", "-c", "--baz" };
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 5, args );
+ opts_parse( Options_Config, NULL, 5, args );
const char** opts = opts_select("baz", "opttag");
CHECK(0 == strcmp("baz", opts[0]));
CHECK(NULL == opts[1]);
char* args[] = { "prog", "-a", "--foo", "-c", "--baz" };
CHECK_DOES_NOT_EXIT()
{
- opts_parse( Options_Config, 5, args );
+ opts_parse( Options_Config, NULL, 5, args );
const char** opts = opts_select(NULL, "opttag");
CHECK(0 == strcmp("baz", opts[0]));
CHECK(0 == strcmp("foo", opts[1]));