]> git.mdlowis.com Git - projs/opts.git/commitdiff
finished new interface
authorMichael D. Lowis <mike@mdlowis.com>
Sat, 4 Oct 2014 20:46:21 +0000 (16:46 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Sat, 4 Oct 2014 20:46:21 +0000 (16:46 -0400)
source/opts.c
source/opts.h
tests/test_opts.c

index a6e2079e638c38c6c5440a47da210fa79cb17959..de760862f560b420ef6fd6a8a311d178e9094568 100755 (executable)
@@ -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;
 }
 
+
index b2233d09ea6c5d0e8dbd683052624a9adea047cc..18022a647eed71a7d6d580a8cf1616d20482bd90 100755 (executable)
@@ -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
 }
index 4be03de667dc78df36d85f4fc3c0e1a858428e43..e9a3b19c2f76ca10c1674cc5f124dc6a6203cbe2 100755 (executable)
 // 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();
+    }
 }