From: Michael D. Lowis Date: Sat, 4 Oct 2014 20:46:21 +0000 (-0400) Subject: finished new interface X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=104cb46db6dfd7758dbb2b29a6b34a50763ffe4f;p=projs%2Fopts.git finished new interface --- diff --git a/source/opts.c b/source/opts.c index a6e2079..de76086 100755 --- a/source/opts.c +++ b/source/opts.c @@ -14,9 +14,6 @@ typedef struct entry_t { struct entry_t* next; } entry_t; -static entry_t* Options = NULL; -static entry_t* Arguments = NULL; - typedef enum { LONG, SHORT } OptionType_T; typedef struct { @@ -28,12 +25,14 @@ 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 ); @@ -48,8 +47,12 @@ static void opts_add_argument(char* arg); 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) { @@ -94,18 +97,9 @@ void opts_reset(void) { } } -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; @@ -114,7 +108,7 @@ static void opts_parse_short_option( StreamContext_T* ctx ) { 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); } @@ -140,8 +134,9 @@ static char* opts_parse_optarg(StreamContext_T* ctx, char* 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); } @@ -151,8 +146,6 @@ static void opts_parse_argument( StreamContext_T* ctx ) { 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; @@ -252,6 +245,7 @@ static void opts_add_argument(char* arg_val) { } /*****************************************************************************/ + option_t* find_option(const char* name, const char* tag) { option_t* p_opt = NULL; entry_t* current = Options; @@ -267,25 +261,46 @@ option_t* find_option(const char* name, const char* tag) { 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; } + diff --git a/source/opts.h b/source/opts.h index b2233d0..18022a6 100755 --- a/source/opts.h +++ b/source/opts.h @@ -23,9 +23,9 @@ bool opts_is_set(const char* name, const char* tag); const char* opts_get_value(const char* name, const char* tag); -size_t opts_num_args(void); +const char** opts_select(const char* name, const char* tag); -const char* opts_get_arg(size_t index); +const char** opts_arguments(void); #ifdef __cplusplus } diff --git a/tests/test_opts.c b/tests/test_opts.c index 4be03de..e9a3b19 100755 --- a/tests/test_opts.c +++ b/tests/test_opts.c @@ -13,12 +13,13 @@ // 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 } }; //----------------------------------------------------------------------------- @@ -246,188 +247,84 @@ TEST_SUITE(Opts) { 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(); + } }