command parser: Add support for parser options.
authorSebastian Harl <sh@tokkee.org>
Wed, 8 Jun 2016 22:37:58 +0000 (00:37 +0200)
committerSebastian Harl <sh@tokkee.org>
Sun, 25 Sep 2016 10:42:45 +0000 (12:42 +0200)
These can be used to tune the parser behavior. For now, there's an option to
specify the default hostname in an identifier.

src/utils_cmd_flush.c
src/utils_cmd_flush.h
src/utils_cmd_getval.c
src/utils_cmd_getval.h
src/utils_cmd_listval.c
src/utils_cmd_listval.h
src/utils_cmd_putval.c
src/utils_cmd_putval.h
src/utils_cmds.c
src/utils_cmds.h
src/utils_cmds_test.c

index 7e26be7..320b063 100644 (file)
 #include "utils_cmd_flush.h"
 
 cmd_status_t cmd_parse_flush (size_t argc, char **argv,
-               cmd_flush_t *ret_flush, cmd_error_handler_t *err)
+               cmd_flush_t *ret_flush, const cmd_options_t *opts,
+               cmd_error_handler_t *err)
 {
-       if (ret_flush == NULL)
+
+       if ((ret_flush == NULL) || (opts == NULL))
        {
                errno = EINVAL;
                cmd_error (CMD_ERROR, err, "Invalid arguments to cmd_parse_flush.");
@@ -83,7 +85,7 @@ cmd_status_t cmd_parse_flush (size_t argc, char **argv,
                        if (parse_identifier (opt_value,
                                                &id->host, &id->plugin, &id->plugin_instance,
                                                &id->type, &id->type_instance,
-                                               NULL) != 0)
+                                               opts->identifier_default_host) != 0)
                        {
                                cmd_error (CMD_PARSE_ERROR, err,
                                                "Invalid identifier `%s'.", opt_value);
@@ -142,7 +144,7 @@ cmd_status_t cmd_handle_flush (FILE *fh, char *buffer)
        DEBUG ("utils_cmd_flush: cmd_handle_flush (fh = %p, buffer = %s);",
                        (void *) fh, buffer);
 
-       if ((status = cmd_parse (buffer, &cmd, &err)) != CMD_OK)
+       if ((status = cmd_parse (buffer, &cmd, NULL, &err)) != CMD_OK)
                return (status);
        if (cmd.type != CMD_FLUSH)
        {
index 2afa3c7..9dbff20 100644 (file)
@@ -32,7 +32,8 @@
 #include "utils_cmds.h"
 
 cmd_status_t cmd_parse_flush (size_t argc, char **argv,
-               cmd_flush_t *ret_flush, cmd_error_handler_t *err);
+               cmd_flush_t *ret_flush, const cmd_options_t *opts,
+               cmd_error_handler_t *err);
 
 cmd_status_t cmd_handle_flush (FILE *fh, char *buffer);
 
index 3a8a2be..f29680a 100644 (file)
 #include "utils_cmd_getval.h"
 
 cmd_status_t cmd_parse_getval (size_t argc, char **argv,
-    cmd_getval_t *ret_getval, cmd_error_handler_t *err)
+    cmd_getval_t *ret_getval, const cmd_options_t *opts,
+    cmd_error_handler_t *err)
 {
   char *identifier_copy;
   int status;
 
+  if ((ret_getval == NULL) || (opts == NULL))
+  {
+    errno = EINVAL;
+    cmd_error (CMD_ERROR, err, "Invalid arguments to cmd_parse_getval.");
+    return (CMD_ERROR);
+  }
+
   if (argc != 1)
   {
     if (argc == 0)
@@ -56,7 +64,7 @@ cmd_status_t cmd_parse_getval (size_t argc, char **argv,
   status = parse_identifier (argv[0], &ret_getval->identifier.host,
       &ret_getval->identifier.plugin, &ret_getval->identifier.plugin_instance,
       &ret_getval->identifier.type, &ret_getval->identifier.type_instance,
-      NULL);
+      opts->identifier_default_host);
   if (status != 0)
   {
     DEBUG ("cmd_parse_getval: Cannot parse identifier `%s'.", identifier_copy);
@@ -99,7 +107,7 @@ cmd_status_t cmd_handle_getval (FILE *fh, char *buffer)
   DEBUG ("utils_cmd_getval: cmd_handle_getval (fh = %p, buffer = %s);",
       (void *) fh, buffer);
 
-  if ((status = cmd_parse (buffer, &cmd, &err)) != CMD_OK)
+  if ((status = cmd_parse (buffer, &cmd, NULL, &err)) != CMD_OK)
     return (status);
   if (cmd.type != CMD_GETVAL)
   {
index 0efaed6..b0c64be 100644 (file)
@@ -32,7 +32,8 @@
 #include "utils_cmds.h"
 
 cmd_status_t cmd_parse_getval (size_t argc, char **argv,
-    cmd_getval_t *ret_getval, cmd_error_handler_t *err);
+    cmd_getval_t *ret_getval, const cmd_options_t *opts,
+    cmd_error_handler_t *err);
 
 cmd_status_t cmd_handle_getval (FILE *fh, char *buffer);
 
index 7e256f0..27b88cb 100644 (file)
@@ -35,6 +35,7 @@
 
 cmd_status_t cmd_parse_listval (size_t argc, char **argv,
     cmd_listval_t *ret_listval __attribute__((unused)),
+    const cmd_options_t *opts __attribute__((unused)),
     cmd_error_handler_t *err)
 {
   if (argc != 0)
@@ -81,7 +82,7 @@ cmd_status_t cmd_handle_listval (FILE *fh, char *buffer)
   DEBUG ("utils_cmd_listval: handle_listval (fh = %p, buffer = %s);",
       (void *) fh, buffer);
 
-  if ((status = cmd_parse (buffer, &cmd, &err)) != CMD_OK)
+  if ((status = cmd_parse (buffer, &cmd, NULL, &err)) != CMD_OK)
     return (status);
   if (cmd.type != CMD_LISTVAL)
   {
index 5d2866d..895878c 100644 (file)
@@ -32,7 +32,8 @@
 #include "utils_cmds.h"
 
 cmd_status_t cmd_parse_listval (size_t argc, char **argv,
-    cmd_listval_t *ret_listval, cmd_error_handler_t *err);
+    cmd_listval_t *ret_listval, const cmd_options_t *opts,
+    cmd_error_handler_t *err);
 
 cmd_status_t cmd_handle_listval (FILE *fh, char *buffer);
 
index 0a0af8a..b253785 100644 (file)
@@ -69,7 +69,8 @@ static int set_option (value_list_t *vl, const char *key, const char *value)
  */
 
 cmd_status_t cmd_parse_putval (size_t argc, char **argv,
-               cmd_putval_t *ret_putval, cmd_error_handler_t *err)
+               cmd_putval_t *ret_putval, const cmd_options_t *opts,
+               cmd_error_handler_t *err)
 {
        cmd_status_t result;
 
@@ -87,6 +88,13 @@ cmd_status_t cmd_parse_putval (size_t argc, char **argv,
        value_list_t vl = VALUE_LIST_INIT;
        size_t i;
 
+       if ((ret_putval == NULL) || (opts == NULL))
+       {
+               errno = EINVAL;
+               cmd_error (CMD_ERROR, err, "Invalid arguments to cmd_parse_putval.");
+               return (CMD_ERROR);
+       }
+
        if (argc < 2)
        {
                cmd_error (CMD_PARSE_ERROR, err,
@@ -103,7 +111,7 @@ cmd_status_t cmd_parse_putval (size_t argc, char **argv,
        status = parse_identifier (identifier, &hostname,
                        &plugin, &plugin_instance,
                        &type, &type_instance,
-                       NULL);
+                       opts->identifier_default_host);
        if (status != 0)
        {
                DEBUG ("cmd_handle_putval: Cannot parse identifier `%s'.",
@@ -257,7 +265,7 @@ cmd_status_t cmd_handle_putval (FILE *fh, char *buffer)
        DEBUG ("utils_cmd_putval: cmd_handle_putval (fh = %p, buffer = %s);",
                        (void *) fh, buffer);
 
-       if ((status = cmd_parse (buffer, &cmd, &err)) != CMD_OK)
+       if ((status = cmd_parse (buffer, &cmd, NULL, &err)) != CMD_OK)
                return (status);
        if (cmd.type != CMD_PUTVAL)
        {
index 363194d..bb0b227 100644 (file)
@@ -33,7 +33,8 @@
 #include "utils_cmds.h"
 
 cmd_status_t cmd_parse_putval (size_t argc, char **argv,
-               cmd_putval_t *ret_putval, cmd_error_handler_t *err);
+               cmd_putval_t *ret_putval, const cmd_options_t *opts,
+               cmd_error_handler_t *err);
 
 cmd_status_t cmd_handle_putval (FILE *fh, char *buffer);
 
index f574c6a..f667596 100644 (file)
 #include <stdbool.h>
 #include <string.h>
 
+static cmd_options_t default_options = {
+       /* identifier_default_host = */ NULL,
+};
+
 /*
  * private helper functions
  */
@@ -195,8 +199,8 @@ void cmd_error (cmd_status_t status, cmd_error_handler_t *err,
        va_end (ap);
 } /* void cmd_error */
 
-cmd_status_t cmd_parsev (size_t argc, char **argv,
-               cmd_t *ret_cmd, cmd_error_handler_t *err)
+cmd_status_t cmd_parsev (size_t argc, char **argv, cmd_t *ret_cmd,
+               const cmd_options_t *opts, cmd_error_handler_t *err)
 {
        char *command = NULL;
        cmd_status_t status;
@@ -208,31 +212,34 @@ cmd_status_t cmd_parsev (size_t argc, char **argv,
                return CMD_ERROR;
        }
 
+       if (opts == NULL)
+               opts = &default_options;
+
        memset (ret_cmd, 0, sizeof (*ret_cmd));
        command = argv[0];
        if (strcasecmp ("FLUSH", command) == 0)
        {
                ret_cmd->type = CMD_FLUSH;
                status = cmd_parse_flush (argc - 1, argv + 1,
-                               &ret_cmd->cmd.flush, err);
+                               &ret_cmd->cmd.flush, opts, err);
        }
        else if (strcasecmp ("GETVAL", command) == 0)
        {
                ret_cmd->type = CMD_GETVAL;
                status = cmd_parse_getval (argc - 1, argv + 1,
-                               &ret_cmd->cmd.getval, err);
+                               &ret_cmd->cmd.getval, opts, err);
        }
        else if (strcasecmp ("LISTVAL", command) == 0)
        {
                ret_cmd->type = CMD_LISTVAL;
                status = cmd_parse_listval (argc - 1, argv + 1,
-                               &ret_cmd->cmd.listval, err);
+                               &ret_cmd->cmd.listval, opts, err);
        }
        else if (strcasecmp ("PUTVAL", command) == 0)
        {
                ret_cmd->type = CMD_PUTVAL;
                status = cmd_parse_putval (argc - 1, argv + 1,
-                               &ret_cmd->cmd.putval, err);
+                               &ret_cmd->cmd.putval, opts, err);
        }
        else
        {
@@ -247,8 +254,8 @@ cmd_status_t cmd_parsev (size_t argc, char **argv,
        return (status);
 } /* cmd_status_t cmd_parsev */
 
-cmd_status_t cmd_parse (char *buffer,
-               cmd_t *ret_cmd, cmd_error_handler_t *err)
+cmd_status_t cmd_parse (char *buffer, cmd_t *ret_cmd,
+               const cmd_options_t *opts, cmd_error_handler_t *err)
 {
        char **fields = NULL;
        size_t fields_num = 0;
@@ -257,7 +264,7 @@ cmd_status_t cmd_parse (char *buffer,
        if ((status = cmd_split (buffer, &fields_num, &fields, err)) != CMD_OK)
                return status;
 
-       status = cmd_parsev (fields_num, fields, ret_cmd, err);
+       status = cmd_parsev (fields_num, fields, ret_cmd, opts, err);
        free (fields);
        return (status);
 } /* cmd_status_t cmd_parse */
index 62cf8a9..205e89a 100644 (file)
@@ -91,6 +91,19 @@ typedef struct {
 
 /*
  * NAME
+ *   cmd_options_t
+ *
+ * DESCRIPTIONS
+ *   Optional settings for tuning the parser behavior.
+ */
+typedef struct {
+       /* identifier_default_host: If non-NULL, the hostname is optional and will
+        * default to the specified value. */
+       char *identifier_default_host;
+} cmd_options_t;
+
+/*
+ * NAME
  *   cmd_status_t
  *
  * DESCRIPTION
@@ -140,16 +153,17 @@ void cmd_error (cmd_status_t status, cmd_error_handler_t *err,
  * PARAMETERS
  *   `buffer'  The command string to be parsed.
  *   `ret_cmd' The parse result will be stored at this location.
+ *   `opts'    Parser options. If NULL, defaults will be used.
  *   `err'     An optional error handler to invoke on error.
  *
  * RETURN VALUE
  *   CMD_OK on success or the respective error code otherwise.
  */
-cmd_status_t cmd_parse (char *buffer,
-               cmd_t *ret_cmd, cmd_error_handler_t *err);
+cmd_status_t cmd_parse (char *buffer, cmd_t *ret_cmd,
+               const cmd_options_t *opts, cmd_error_handler_t *err);
 
-cmd_status_t cmd_parsev (size_t argc, char **argv,
-               cmd_t *ret_cmd, cmd_error_handler_t *err);
+cmd_status_t cmd_parsev (size_t argc, char **argv, cmd_t *ret_cmd,
+               const cmd_options_t *opts, cmd_error_handler_t *err);
 
 void cmd_destroy (cmd_t *cmd);
 
index 68b5140..f5743e9 100644 (file)
@@ -40,49 +40,74 @@ static void error_cb (void *ud, cmd_status_t status,
        fflush (stdout);
 } /* void error_cb */
 
-struct {
+static cmd_options_t default_host_opts = {
+       /* identifier_default_host = */ "dummy-host",
+};
+
+static struct {
        char *input;
+       cmd_options_t *opts;
        cmd_status_t expected_status;
        cmd_type_t expected_type;
 } parse_data[] = {
        /* Valid FLUSH commands. */
        {
                "FLUSH",
+               NULL,
                CMD_OK,
                CMD_FLUSH,
        },
        {
                "FLUSH identifier=myhost/magic/MAGIC",
+               NULL,
+               CMD_OK,
+               CMD_FLUSH,
+       },
+       {
+               "FLUSH identifier=magic/MAGIC",
+               &default_host_opts,
                CMD_OK,
                CMD_FLUSH,
        },
        {
                "FLUSH timeout=123 plugin=\"A\"",
+               NULL,
                CMD_OK,
                CMD_FLUSH,
        },
        /* Invalid FLUSH commands. */
        {
+               /* Missing hostname; no default. */
+               "FLUSH identifier=magic/MAGIC",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
                /* Missing 'identifier' key. */
                "FLUSH myhost/magic/MAGIC",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
        {
                /* Invalid timeout. */
                "FLUSH timeout=A",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
        {
                /* Invalid identifier. */
                "FLUSH identifier=invalid",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
        {
                /* Invalid option. */
                "FLUSH invalid=option",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
@@ -90,18 +115,33 @@ struct {
        /* Valid GETVAL commands. */
        {
                "GETVAL myhost/magic/MAGIC",
+               NULL,
+               CMD_OK,
+               CMD_GETVAL,
+       },
+       {
+               "GETVAL magic/MAGIC",
+               &default_host_opts,
                CMD_OK,
                CMD_GETVAL,
        },
 
        /* Invalid GETVAL commands. */
        {
+               "GETVAL magic/MAGIC",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
                "GETVAL",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
        {
                "GETVAL invalid",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
@@ -109,6 +149,7 @@ struct {
        /* Valid LISTVAL commands. */
        {
                "LISTVAL",
+               NULL,
                CMD_OK,
                CMD_LISTVAL,
        },
@@ -116,70 +157,95 @@ struct {
        /* Invalid LISTVAL commands. */
        {
                "LISTVAL invalid",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
 
        /* Valid PUTVAL commands. */
        {
+               "PUTVAL magic/MAGIC N:42",
+               &default_host_opts,
+               CMD_OK,
+               CMD_PUTVAL,
+       },
+       {
                "PUTVAL myhost/magic/MAGIC N:42",
+               NULL,
                CMD_OK,
                CMD_PUTVAL,
        },
        {
                "PUTVAL myhost/magic/MAGIC 1234:42",
+               NULL,
                CMD_OK,
                CMD_PUTVAL,
        },
        {
                "PUTVAL myhost/magic/MAGIC 1234:42 2345:23",
+               NULL,
                CMD_OK,
                CMD_PUTVAL,
        },
        {
                "PUTVAL myhost/magic/MAGIC interval=2 1234:42",
+               NULL,
                CMD_OK,
                CMD_PUTVAL,
        },
        {
                "PUTVAL myhost/magic/MAGIC interval=2 1234:42 interval=5 2345:23",
+               NULL,
                CMD_OK,
                CMD_PUTVAL,
        },
 
        /* Invalid PUTVAL commands. */
        {
+               "PUTVAL magic/MAGIC N:42",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
                "PUTVAL",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
        {
                "PUTVAL invalid N:42",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
        {
                "PUTVAL myhost/magic/MAGIC A:42",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
        {
                "PUTVAL myhost/magic/MAGIC 1234:A",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
        {
                "PUTVAL myhost/magic/MAGIC",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
        {
                "PUTVAL 1234:A",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
        {
                "PUTVAL myhost/magic/UNKNOWN 1234:42",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
@@ -187,6 +253,7 @@ struct {
         * As of collectd 5.x, PUTVAL accepts invalid options.
        {
                "PUTVAL myhost/magic/MAGIC invalid=2 1234:42",
+               NULL,
                CMD_PARSE_ERROR,
                CMD_UNKNOWN,
        },
@@ -195,11 +262,13 @@ struct {
        /* Invalid commands. */
        {
                "INVALID",
+               NULL,
                CMD_UNKNOWN_COMMAND,
                CMD_UNKNOWN,
        },
        {
                "INVALID interval=2",
+               NULL,
                CMD_UNKNOWN_COMMAND,
                CMD_UNKNOWN,
        },
@@ -222,10 +291,10 @@ DEF_TEST(parse)
 
                memset (&cmd, 0, sizeof (cmd));
 
-               status = cmd_parse (input, &cmd, &err);
+               status = cmd_parse (input, &cmd, parse_data[i].opts, &err);
                snprintf (description, sizeof (description),
-                               "cmd_parse (\"%s\") = %d (type=%d [%s]); want %d (type=%d [%s])",
-                               parse_data[i].input, status,
+                               "cmd_parse (\"%s\", opts=%p) = %d (type=%d [%s]); want %d (type=%d [%s])",
+                               parse_data[i].input, parse_data[i].opts, status,
                                cmd.type, CMD_TO_STRING (cmd.type),
                                parse_data[i].expected_status,
                                parse_data[i].expected_type,