struct entry_t* next;
} entry_t;
-static entry_t* Options = NULL;
-static entry_t* Arguments = NULL;
-
typedef enum { LONG, SHORT } OptionType_T;
typedef struct {
OptionConfig_T* options;
} StreamContext_T;
-static void opts_init_context( StreamContext_T* ctx, int argc, char** argv );
+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, const char* opt_name);
+static void opts_parse_error(const char* msg, char* opt_name);
static OptionConfig_T* opts_get_option_config( OptionConfig_T* opts, OptionType_T typ, char* name );
static char* opts_next_token( StreamContext_T* ctx );
void opts_parse( OptionConfig_T* opts, int argc, char** argv ) {
/* Setup the stream */
StreamContext_T ctx;
- ctx.options = opts;
- opts_init_context( &ctx, argc, argv );
+ ctx.line_idx = 0;
+ ctx.col_idx = -1;
+ ctx.arg_count = argc;
+ ctx.arg_vect = argv;
+ ctx.options = opts;
+ (void)opts_next_char( &ctx ); /* Loads up the first char */
/* Until we run out of characters */
while (ctx.current != EOF) {
}
}
-static void opts_init_context( StreamContext_T* ctx, int argc, char** argv ) {
- // Setup the char stream
- ctx->line_idx = 0;
- ctx->col_idx = -1;
- ctx->arg_count = argc;
- ctx->arg_vect = argv;
- (void)opts_next_char( ctx ); // Loads up the first char
-}
-
static void opts_parse_short_option( StreamContext_T* ctx ) {
- // Get Config
- char opt_name[2] = { ctx->current, '\0' };
+ char opt[2] = { ctx->current, '\0' };
+ char* opt_name = strclone(opt);
OptionConfig_T* config = opts_get_option_config( ctx->options, SHORT, opt_name );
if (config != NULL) {
char* opt_arg = NULL;
opt_arg = opts_parse_optarg( ctx, opt_name );
else if ((' ' != ctx->current) && (EOF != ctx->current))
opts_parse_short_option( ctx );
- opts_add_option( strclone(opt_name), config->tag, opt_arg );
+ opts_add_option( opt_name, config->tag, opt_arg );
} else {
opts_parse_error("Unknown Option", opt_name);
}
return opts_next_token( ctx );
}
-static void opts_parse_error(const char* msg, const char* opt_name) {
+static void opts_parse_error(const char* msg, char* opt_name) {
fprintf(stderr, "Option '%s' : %s\n", opt_name, msg);
+ free(opt_name);
exit(1);
}
opts_add_argument(arg_val);
}
-
-
static OptionConfig_T* opts_get_option_config( OptionConfig_T* opts, OptionType_T type, char* name ) {
OptionConfig_T* cfg = NULL;
int i = 0;
}
/*****************************************************************************/
+
option_t* find_option(const char* name, const char* tag) {
option_t* p_opt = NULL;
entry_t* current = Options;
return p_opt;
}
-bool opts_is_set(const char* name, const char* tag)
-{
+bool opts_is_set(const char* name, const char* tag) {
return (NULL != find_option(name,tag));
}
-const char* opts_get_value(const char* name, const char* tag)
-{
+const char* opts_get_value(const char* name, const char* tag) {
option_t* p_opt = find_option(name,tag);
return (NULL == p_opt) ? NULL : p_opt->value;
}
-size_t opts_num_args(void)
-{
- return 0;
+const char** opts_select(const char* name, const char* tag) {
+ size_t index = 0;
+ const char** ret = (const char**)malloc(sizeof(const char*));
+ ret[index] = NULL;
+
+ entry_t* current = Options;
+ while (current != NULL) {
+ option_t* curr_opt = (option_t*)current->value;
+ if (((NULL == name) || (0 == strcmp(name, curr_opt->name))) &&
+ ((NULL == tag) || (0 == strcmp(tag, curr_opt->tag)))) {
+ ret = (const char**)realloc(ret, (index+2)*sizeof(const char*));
+ ret[index++] = curr_opt->value;
+ ret[index] = NULL;
+ }
+ current = current->next;
+ }
+
+ return ret;
}
-const char* opts_get_arg(size_t index)
-{
- (void)index;
- return NULL;
+const char** opts_arguments(void) {
+ size_t index = 0;
+ const char** ret = (const char**)malloc(sizeof(const char*));
+ entry_t* entry = Arguments;
+ while (NULL != entry) {
+ ret = (const char**)realloc(ret, (index+2)*sizeof(const char*));
+ ret[index++] = (const char*)entry->value;
+ ret[index] = NULL;
+ entry = entry->next;
+ }
+ return ret;
}
+
// Sample Option Configuration
//-----------------------------------------------------------------------------
OptionConfig_T Options_Config[] = {
- { (char*)"a", false, (char*)"test_a", (char*)"A simple test option" },
- { (char*)"b", true, (char*)"test_b", (char*)"A simple test option" },
- { (char*)"c", false, (char*)"test_c", (char*)"A simple test option" },
- { (char*)"foo", false, (char*)"test_d", (char*)"A simple test option" },
- { (char*)"bar", true, (char*)"test_e", (char*)"A simple test option" },
- { (char*)NULL, false, (char*)NULL, (char*)NULL }
+ { "a", false, "test_a", "A simple test option" },
+ { "b", true, "test_b", "A simple test option" },
+ { "c", false, "test_c", "A simple test option" },
+ { "foo", false, "opttag", "A simple test option" },
+ { "bar", true, "test_e", "A simple test option" },
+ { "baz", false, "opttag", "A simple test option" },
+ { NULL, false, NULL, NULL }
};
//-----------------------------------------------------------------------------
CHECK_DOES_NOT_EXIT()
{
opts_parse( Options_Config, 1, args );
+ const char** args = opts_arguments();
+ CHECK(0 == strcmp("baz1", args[0]));
+ CHECK(NULL == args[1]);
+ free(args);
}
opts_reset();
}
+ TEST(Verify_ParseOptions_Parses_Multiple_Floating_Arguments)
+ {
+ char* args[] = { "baz1", "baz2" };
+ CHECK_DOES_NOT_EXIT()
+ {
+ opts_parse( Options_Config, 2, args );
+ const char** args = opts_arguments();
+ CHECK(0 == strcmp("baz2", args[0]));
+ CHECK(0 == strcmp("baz1", args[1]));
+ CHECK(NULL == args[2]);
+ free(args);
+ }
+ opts_reset();
+ }
+ TEST(Verify_Select_returns_the_matching_option_by_name)
+ {
+ char* args[] = { "-a", "--foo", "-c" };
+ CHECK_DOES_NOT_EXIT()
+ {
+ opts_parse( Options_Config, 3, args );
+ const char** opts = opts_select("c", NULL);
+ CHECK(0 == strcmp("c", opts[0]));
+ CHECK(NULL == opts[1]);
+ free(opts);
+ }
+ opts_reset();
+ }
+ TEST(Verify_Select_returns_the_matching_option_by_tag)
+ {
+ char* args[] = { "-a", "--foo", "-c" };
+ CHECK_DOES_NOT_EXIT()
+ {
+ opts_parse( Options_Config, 3, args );
+ const char** opts = opts_select(NULL, "test_c");
+ CHECK(0 == strcmp("c", opts[0]));
+ CHECK(NULL == opts[1]);
+ free(opts);
+ }
+ opts_reset();
+ }
+ TEST(Verify_Select_returns_the_matching_option_by_name_and_tag)
+ {
+ char* args[] = { "-a", "--foo", "-c", "--baz" };
+ CHECK_DOES_NOT_EXIT()
+ {
+ opts_parse( Options_Config, 4, args );
+ const char** opts = opts_select("baz", "opttag");
+ CHECK(0 == strcmp("baz", opts[0]));
+ CHECK(NULL == opts[1]);
+ free(opts);
+ }
+ opts_reset();
+ }
-
-
-
-
-
-
-// TEST(Verify_ParseOptions_exits_when_a_short_option_lacks_the_required_option)
-// {
-// Result_T* results;
-// int exit_code = 0;
-// char* args[] = { (char*)"-b-" };
-//
-// exit_code = setjmp( Exit_Point );
-// if( 0 == exit_code ) {
-// results = opts_parse( Options_Config, 1, args );
-// // If we fail to call exit then this breaks our test
-// CHECK( false );
-// } else {
-// CHECK( 1 == exit_code );
-// }
-// }
-//
-// TEST(Verify_ParseOptions_exits_when_a_short_option_with_no_accompanying_option)
-// {
-// Result_T* results;
-// int exit_code = 0;
-// char* args[] = { (char*)"-b" };
-//
-// exit_code = setjmp( Exit_Point );
-// if( 0 == exit_code ) {
-// results = opts_parse( Options_Config, 1, args );
-// // If we fail to call exit then this breaks our test
-// CHECK( false );
-// } else {
-// CHECK( 1 == exit_code );
-// }
-// }
-//
-// TEST(Verify_ParseOptions_errors_on_unknown_option)
-// {
-// Result_T* results;
-// int exit_code = 0;
-// char* args[] = { (char*)"-z" };
-//
-// exit_code = setjmp( Exit_Point );
-// if( 0 == exit_code ) {
-// results = opts_parse( Options_Config, 1, args );
-// // If we fail to call exit then this breaks our test
-// CHECK( false );
-// } else {
-// CHECK( 1 == exit_code );
-// }
-// }
-//
-// TEST(Verify_ParseOptions_Parses_short_option_group)
-// {
-// char* args[] = { (char*)"-aa" };
-//
-// CHECK_DOES_NOT_EXIT()
-// {
-// Result_T* results = opts_parse( Options_Config, 1, args );
-//
-// OptionList_T* result = results->options;
-// CHECK( NULL != result );
-// CHECK( NULL != result->head );
-// CHECK( NULL != result->tail );
-// CHECK( result->head != result->tail );
-// CHECK( NULL != result->head->key );
-// CHECK( 0 == strcmp( result->head->key, "a" ) );
-// CHECK( NULL == result->head->val );
-// CHECK( NULL != result->tail->key );
-// CHECK( 0 == strcmp( result->tail->key, "a" ) );
-// CHECK( NULL == result->tail->val );
-// }
-// }
-//
-// TEST(Verify_ParseOptions_Parses_short_option_group_with_more_than_2_options)
-// {
-// char* args[] = { (char*)"-aaaa" };
-//
-// CHECK_DOES_NOT_EXIT()
-// {
-// Result_T* results = opts_parse( Options_Config, 1, args );
-//
-// OptionList_T* result = results->options;
-// CHECK( NULL != result );
-// CHECK( NULL != result->head );
-// CHECK( NULL != result->tail );
-// CHECK( result->head != result->tail );
-// }
-// }
-//
-// TEST(Verify_ParseOptions_Parses_short_option_group_with_the_last_having_an_arg)
-// {
-// char* args[] = { (char*)"-ab5" };
-//
-// CHECK_DOES_NOT_EXIT()
-// {
-// Result_T* results = opts_parse( Options_Config, 1, args );
-// OptionList_T* result = results->options;
-// CHECK( NULL != result );
-// CHECK( NULL != result->head );
-// CHECK( NULL != result->tail );
-// CHECK( result->head != result->tail );
-// CHECK( NULL != result->head->key );
-// CHECK( 0 == strcmp( result->head->key, "b" ) );
-// CHECK( NULL != result->head->val );
-// CHECK( 0 == strcmp( result->head->val, "5" ) );
-// CHECK( NULL != result->tail->key );
-// CHECK( 0 == strcmp( result->tail->key, "a" ) );
-// CHECK( NULL == result->tail->val );
-// }
-// }
-//
-// TEST(Verify_ParseOptions_Parses_A_Short_Option_With_No_Param)
-// {
-// char* args[] = { (char*)"-a" };
-//
-// CHECK_DOES_NOT_EXIT()
-// {
-// Result_T* results = opts_parse( Options_Config, 1, args );
-//
-// OptionList_T* result = results->options;
-// CHECK( NULL != result );
-// CHECK( NULL != result->head );
-// CHECK( NULL != result->tail );
-// CHECK( result->head == result->tail );
-// CHECK( NULL != result->tail->key );
-// CHECK( 0 == strcmp( result->tail->key, "a" ) );
-// CHECK( NULL == result->tail->val );
-// CHECK( NULL == result->tail->next );
-// }
-// }
-//
-// TEST(Verify_ParseOptions_Parses_A_Short_Option_With_A_Param_And_A_Space)
-// {
-// char* args[] = { (char*)"-b", (char*)"5" };
-//
-// CHECK_DOES_NOT_EXIT()
-// {
-// Result_T* results = opts_parse( Options_Config, 2, args );
-//
-// OptionList_T* result = results->options;
-// CHECK( NULL != result );
-// CHECK( NULL != result->head );
-// CHECK( NULL != result->tail );
-// CHECK( result->head == result->tail );
-// CHECK( NULL != result->tail->key );
-// CHECK( 0 == strcmp( result->tail->key, "b" ) );
-// CHECK( NULL != result->tail->val );
-// CHECK( 0 == strcmp( result->tail->val, "5" ) );
-// CHECK( NULL == result->tail->next );
-// }
-// }
-//
-// TEST(Verify_ParseOptions_Parses_A_Short_Option_With_A_Param_And_No_Space)
-// {
-// char* args[] = { (char*)"-b5" };
-//
-// CHECK_DOES_NOT_EXIT()
-// {
-// Result_T* results = opts_parse( Options_Config, 1, args );
-//
-// OptionList_T* result = results->options;
-// CHECK( NULL != result );
-// CHECK( NULL != result->head );
-// CHECK( NULL != result->tail );
-// CHECK( result->head == result->tail );
-// CHECK( NULL != result->tail->key );
-// CHECK( 0 == strcmp( result->tail->key, "b" ) );
-// CHECK( NULL != result->tail->val );
-// CHECK( 0 == strcmp( result->tail->val, "5" ) );
-// CHECK( NULL == result->tail->next );
-// }
-// }
+ TEST(Verify_Select_returns_the_matching_options_by_tag)
+ {
+ char* args[] = { "-a", "--foo", "-c", "--baz" };
+ CHECK_DOES_NOT_EXIT()
+ {
+ opts_parse( Options_Config, 4, args );
+ const char** opts = opts_select(NULL, "opttag");
+ CHECK(0 == strcmp("baz", opts[0]));
+ CHECK(0 == strcmp("foo", opts[1]));
+ CHECK(NULL == opts[2]);
+ free(opts);
+ }
+ opts_reset();
+ }
}