]> git.mdlowis.com Git - projs/opts.git/commitdiff
Added the ability for the user to provide their own error handler
authorMike D. Lowis <mike@mdlowis.com>
Thu, 19 Mar 2015 15:06:42 +0000 (11:06 -0400)
committerMike D. Lowis <mike@mdlowis.com>
Thu, 19 Mar 2015 15:06:42 +0000 (11:06 -0400)
source/opts.c
source/opts.h
tests/test_opts.c

index db00d7a40dcf8663b3e1d6b13c94903a09d29861..02bbf57d1239a4c781d691d9a56f9e9e734056a2 100755 (executable)
@@ -25,27 +25,26 @@ typedef struct {
     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;
@@ -55,6 +54,10 @@ void opts_parse( opts_cfg_t* opts, int argc, char** argv ) {
     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];
 
@@ -114,7 +117,7 @@ static void opts_parse_short_option( StreamContext_T* ctx ) {
             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);
     }
 }
 
@@ -127,14 +130,14 @@ static void opts_parse_long_option( StreamContext_T* ctx ) {
             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 );
 }
 
@@ -350,3 +353,4 @@ void opts_print_help(FILE* ofile, opts_cfg_t* opts) {
     free(buffer);
     exit(1);
 }
+
index 461eb0c6d766f69ee0d4a7be2bd41b356ecb8aa5..a6c41661f529012ede19df7397479000ba48da5c 100755 (executable)
@@ -66,6 +66,8 @@ typedef struct {
     char* desc;
 } opts_cfg_t;
 
+typedef void (*opts_err_cbfn_t)(const char* msg, char* opt_name);
+
 /**
  * Parse the command line options using the provided option definition list.
  *
@@ -73,7 +75,7 @@ typedef struct {
  * @param argc The number of arguments in the vector
  * @param argv The vector of command line arguments
  */
-void opts_parse(opts_cfg_t* opts, int argc, char** argv);
+void opts_parse(opts_cfg_t* opts, opts_err_cbfn_t err_cb, int argc, char** argv);
 
 /**
  * Resets the global state back to defaults. This includes freeing any
index 3be93f67d478bfcb6bafd8a5a15580ae1c8e914b..e8cb4618c6d718a5d32e5b0a2948c13043c3f532 100755 (executable)
@@ -39,6 +39,13 @@ void exit(int code)
     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) {}
 
 //-----------------------------------------------------------------------------
@@ -53,7 +60,7 @@ TEST_SUITE(Opts) {
         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();
@@ -65,7 +72,7 @@ TEST_SUITE(Opts) {
 
         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)));
         }
@@ -77,7 +84,7 @@ TEST_SUITE(Opts) {
         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)));
         }
@@ -91,7 +98,7 @@ TEST_SUITE(Opts) {
 
         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 {
@@ -107,7 +114,7 @@ TEST_SUITE(Opts) {
 
         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 {
@@ -123,7 +130,7 @@ TEST_SUITE(Opts) {
 
         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 {
@@ -137,7 +144,7 @@ TEST_SUITE(Opts) {
         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();
@@ -148,7 +155,7 @@ TEST_SUITE(Opts) {
         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));
         }
@@ -160,7 +167,7 @@ TEST_SUITE(Opts) {
         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)));
         }
@@ -172,7 +179,7 @@ TEST_SUITE(Opts) {
         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)));
         }
@@ -184,7 +191,7 @@ TEST_SUITE(Opts) {
         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)));
         }
@@ -199,7 +206,7 @@ TEST_SUITE(Opts) {
 
         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 {
@@ -215,7 +222,7 @@ TEST_SUITE(Opts) {
 
         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 {
@@ -231,7 +238,7 @@ TEST_SUITE(Opts) {
 
         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 {
@@ -246,7 +253,7 @@ TEST_SUITE(Opts) {
 
         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]);
@@ -261,7 +268,7 @@ TEST_SUITE(Opts) {
 
         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]));
@@ -271,12 +278,28 @@ TEST_SUITE(Opts) {
         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]);
@@ -290,7 +313,7 @@ TEST_SUITE(Opts) {
         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]);
@@ -304,7 +327,7 @@ TEST_SUITE(Opts) {
         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]);
@@ -318,7 +341,7 @@ TEST_SUITE(Opts) {
         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]));