MXS-929: Add descriptions to module command arguments
Each argument now has a description describing what it does and what it's used for.
This commit is contained in:
@ -35,26 +35,37 @@ MXS_BEGIN_DECLS
|
|||||||
/**
|
/**
|
||||||
* The argument type
|
* The argument type
|
||||||
*
|
*
|
||||||
* First 8 bits are reserved for argument type, bits 9 through 32 are reserved
|
* First 8 bits of @c value are reserved for argument type, bits 9 through
|
||||||
* for argument options and bits 33 through 64 are reserved for future use.
|
* 32 are reserved for argument options and bits 33 through 64 are reserved
|
||||||
|
* for future use.
|
||||||
|
*
|
||||||
|
* @c description should be a human-readable description of the argument.
|
||||||
*/
|
*/
|
||||||
typedef uint64_t modulecmd_arg_type_t;
|
typedef struct
|
||||||
|
{
|
||||||
|
uint64_t type; /**< The argument type */
|
||||||
|
const char *description; /**< The argument description */
|
||||||
|
} modulecmd_arg_type_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Argument types for the registered functions, the first 8 bits of
|
* Argument types for the registered functions, the first 8 bits of
|
||||||
* the modulecmd_arg_type_t type. An argument can be of only one type.
|
* the modulecmd_arg_type_t type's @c value member. An argument can be of
|
||||||
|
* only one type.
|
||||||
*/
|
*/
|
||||||
#define MODULECMD_ARG_NONE 0
|
#define MODULECMD_ARG_NONE 0 /**< Empty argument */
|
||||||
#define MODULECMD_ARG_STRING 1
|
#define MODULECMD_ARG_STRING 1 /**< String */
|
||||||
#define MODULECMD_ARG_BOOLEAN 2
|
#define MODULECMD_ARG_BOOLEAN 2 /**< Boolean value */
|
||||||
#define MODULECMD_ARG_SERVICE 3
|
#define MODULECMD_ARG_SERVICE 3 /**< Service name */
|
||||||
#define MODULECMD_ARG_SERVER 4
|
#define MODULECMD_ARG_SERVER 4 /**< Server name */
|
||||||
#define MODULECMD_ARG_SESSION 5
|
#define MODULECMD_ARG_SESSION 5 /**< SESSION pointer in string format */
|
||||||
#define MODULECMD_ARG_SESSION_PTR 6
|
#define MODULECMD_ARG_SESSION_PTR 6 /**< Raw SESSION pointer */
|
||||||
#define MODULECMD_ARG_DCB 7
|
#define MODULECMD_ARG_DCB 7 /**< DCB pointer in string format*/
|
||||||
#define MODULECMD_ARG_DCB_PTR 8
|
#define MODULECMD_ARG_DCB_PTR 8 /**< Raw DCB pointer*/
|
||||||
#define MODULECMD_ARG_MONITOR 9
|
#define MODULECMD_ARG_MONITOR 9 /**< Monitor name */
|
||||||
#define MODULECMD_ARG_FILTER 10
|
#define MODULECMD_ARG_FILTER 10 /**< Filter name */
|
||||||
|
#define MODULECMD_ARG_OUTPUT 11 /**< DCB suitable for writing results to.
|
||||||
|
This should always be the first argument
|
||||||
|
if the function requires an output DCB. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for arguments, bits 9 through 32
|
* Options for arguments, bits 9 through 32
|
||||||
@ -64,8 +75,9 @@ typedef uint64_t modulecmd_arg_type_t;
|
|||||||
/**
|
/**
|
||||||
* Helper macros
|
* Helper macros
|
||||||
*/
|
*/
|
||||||
#define MODULECMD_GET_TYPE(type) ((type & 0xff))
|
#define MODULECMD_GET_TYPE(t) ((t)->type & 0xff)
|
||||||
#define MODULECMD_ARG_IS_REQUIRED(type) ((type & MODULECMD_ARG_OPTIONAL) == 0)
|
#define MODULECMD_ARG_IS_REQUIRED(t) (((t)->type & MODULECMD_ARG_OPTIONAL) == 0)
|
||||||
|
#define MODULECMD_ARG_PRESENT(t) (MODULECMD_GET_TYPE(t) != MODULECMD_ARG_NONE)
|
||||||
|
|
||||||
/** Argument list node */
|
/** Argument list node */
|
||||||
struct arg_node
|
struct arg_node
|
||||||
@ -158,6 +170,18 @@ MODULECMD_ARG* modulecmd_arg_parse(const MODULECMD *cmd, int argc, const void **
|
|||||||
*/
|
*/
|
||||||
void modulecmd_arg_free(MODULECMD_ARG *arg);
|
void modulecmd_arg_free(MODULECMD_ARG *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if an optional argument was defined
|
||||||
|
*
|
||||||
|
* This function looks the argument list @c arg at an offset of @c idx and
|
||||||
|
* checks if the argument list contains a value for an optional argument.
|
||||||
|
*
|
||||||
|
* @param arg Argument list
|
||||||
|
* @param idx Index of the argument, starts at 0
|
||||||
|
* @return True if the optional argument is present
|
||||||
|
*/
|
||||||
|
bool modulecmd_arg_is_present(const MODULECMD_ARG *arg, int idx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Call a registered command
|
* @brief Call a registered command
|
||||||
*
|
*
|
||||||
@ -216,4 +240,15 @@ const char* modulecmd_get_error();
|
|||||||
bool modulecmd_foreach(const char *domain_re, const char *ident_re,
|
bool modulecmd_foreach(const char *domain_re, const char *ident_re,
|
||||||
bool(*fn)(const MODULECMD *cmd, void *data), void *data);
|
bool(*fn)(const MODULECMD *cmd, void *data), void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return argument type as string
|
||||||
|
*
|
||||||
|
* This returns the string type of @c type. The returned string must be freed
|
||||||
|
* by the called.
|
||||||
|
*
|
||||||
|
* @param type Type to convert
|
||||||
|
* @return New string or NULL on memory allocation error
|
||||||
|
*/
|
||||||
|
char* modulecmd_argtype_to_str(modulecmd_arg_type_t *type);
|
||||||
|
|
||||||
MXS_END_DECLS
|
MXS_END_DECLS
|
||||||
|
@ -147,7 +147,7 @@ static MODULECMD* command_create(const char *identifier, const char *domain,
|
|||||||
|
|
||||||
for (int i = 0; i < argc; i++)
|
for (int i = 0; i < argc; i++)
|
||||||
{
|
{
|
||||||
if (MODULECMD_ARG_IS_REQUIRED(argv[i]))
|
if (MODULECMD_ARG_IS_REQUIRED(&argv[i]))
|
||||||
{
|
{
|
||||||
argc_min++;
|
argc_min++;
|
||||||
}
|
}
|
||||||
@ -197,14 +197,14 @@ static bool domain_has_command(MODULECMD_DOMAIN *dm, const char *id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool process_argument(modulecmd_arg_type_t type, const void* value,
|
static bool process_argument(modulecmd_arg_type_t *type, const void* value,
|
||||||
struct arg_node *arg, const char **err)
|
struct arg_node *arg, const char **err)
|
||||||
{
|
{
|
||||||
bool rval = false;
|
bool rval = false;
|
||||||
|
|
||||||
if (!MODULECMD_ARG_IS_REQUIRED(type) && value == NULL)
|
if (!MODULECMD_ARG_IS_REQUIRED(type) && value == NULL)
|
||||||
{
|
{
|
||||||
arg->type = MODULECMD_ARG_NONE;
|
arg->type.type = MODULECMD_ARG_NONE;
|
||||||
rval = true;
|
rval = true;
|
||||||
}
|
}
|
||||||
else if (value)
|
else if (value)
|
||||||
@ -212,14 +212,14 @@ static bool process_argument(modulecmd_arg_type_t type, const void* value,
|
|||||||
switch (MODULECMD_GET_TYPE(type))
|
switch (MODULECMD_GET_TYPE(type))
|
||||||
{
|
{
|
||||||
case MODULECMD_ARG_NONE:
|
case MODULECMD_ARG_NONE:
|
||||||
arg->type = MODULECMD_ARG_NONE;
|
arg->type.type = MODULECMD_ARG_NONE;
|
||||||
rval = true;
|
rval = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MODULECMD_ARG_STRING:
|
case MODULECMD_ARG_STRING:
|
||||||
if ((arg->value.string = MXS_STRDUP((char*)value)))
|
if ((arg->value.string = MXS_STRDUP((char*)value)))
|
||||||
{
|
{
|
||||||
arg->type = MODULECMD_ARG_STRING;
|
arg->type.type = MODULECMD_ARG_STRING;
|
||||||
rval = true;
|
rval = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -234,7 +234,7 @@ static bool process_argument(modulecmd_arg_type_t type, const void* value,
|
|||||||
if (truthval != -1)
|
if (truthval != -1)
|
||||||
{
|
{
|
||||||
arg->value.boolean = truthval;
|
arg->value.boolean = truthval;
|
||||||
arg->type = MODULECMD_ARG_BOOLEAN;
|
arg->type.type = MODULECMD_ARG_BOOLEAN;
|
||||||
rval = true;
|
rval = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -247,7 +247,7 @@ static bool process_argument(modulecmd_arg_type_t type, const void* value,
|
|||||||
case MODULECMD_ARG_SERVICE:
|
case MODULECMD_ARG_SERVICE:
|
||||||
if ((arg->value.service = service_find((char*)value)))
|
if ((arg->value.service = service_find((char*)value)))
|
||||||
{
|
{
|
||||||
arg->type = MODULECMD_ARG_SERVICE;
|
arg->type.type = MODULECMD_ARG_SERVICE;
|
||||||
rval = true;
|
rval = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -259,7 +259,7 @@ static bool process_argument(modulecmd_arg_type_t type, const void* value,
|
|||||||
case MODULECMD_ARG_SERVER:
|
case MODULECMD_ARG_SERVER:
|
||||||
if ((arg->value.server = server_find_by_unique_name((char*)value)))
|
if ((arg->value.server = server_find_by_unique_name((char*)value)))
|
||||||
{
|
{
|
||||||
arg->type = MODULECMD_ARG_SERVER;
|
arg->type.type = MODULECMD_ARG_SERVER;
|
||||||
rval = true;
|
rval = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -269,25 +269,25 @@ static bool process_argument(modulecmd_arg_type_t type, const void* value,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MODULECMD_ARG_SESSION:
|
case MODULECMD_ARG_SESSION:
|
||||||
arg->type = MODULECMD_ARG_SESSION;
|
arg->type.type = MODULECMD_ARG_SESSION;
|
||||||
arg->value.session = (SESSION*)strtol((char*)value, NULL, 0);
|
arg->value.session = (SESSION*)strtol((char*)value, NULL, 0);
|
||||||
rval = true;
|
rval = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MODULECMD_ARG_SESSION_PTR:
|
case MODULECMD_ARG_SESSION_PTR:
|
||||||
arg->type = MODULECMD_ARG_SESSION_PTR;
|
arg->type.type = MODULECMD_ARG_SESSION_PTR;
|
||||||
arg->value.session = (SESSION*)value;
|
arg->value.session = (SESSION*)value;
|
||||||
rval = true;
|
rval = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MODULECMD_ARG_DCB:
|
case MODULECMD_ARG_DCB:
|
||||||
arg->type = MODULECMD_ARG_DCB;
|
arg->type.type = MODULECMD_ARG_DCB;
|
||||||
arg->value.dcb = (DCB*)strtol((char*)value, NULL, 0);
|
arg->value.dcb = (DCB*)strtol((char*)value, NULL, 0);
|
||||||
rval = true;
|
rval = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MODULECMD_ARG_DCB_PTR:
|
case MODULECMD_ARG_DCB_PTR:
|
||||||
arg->type = MODULECMD_ARG_DCB_PTR;
|
arg->type.type = MODULECMD_ARG_DCB_PTR;
|
||||||
arg->value.dcb = (DCB*)value;
|
arg->value.dcb = (DCB*)value;
|
||||||
rval = true;
|
rval = true;
|
||||||
break;
|
break;
|
||||||
@ -295,7 +295,7 @@ static bool process_argument(modulecmd_arg_type_t type, const void* value,
|
|||||||
case MODULECMD_ARG_MONITOR:
|
case MODULECMD_ARG_MONITOR:
|
||||||
if ((arg->value.monitor = monitor_find((char*)value)))
|
if ((arg->value.monitor = monitor_find((char*)value)))
|
||||||
{
|
{
|
||||||
arg->type = MODULECMD_ARG_MONITOR;
|
arg->type.type = MODULECMD_ARG_MONITOR;
|
||||||
rval = true;
|
rval = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -307,7 +307,7 @@ static bool process_argument(modulecmd_arg_type_t type, const void* value,
|
|||||||
case MODULECMD_ARG_FILTER:
|
case MODULECMD_ARG_FILTER:
|
||||||
if ((arg->value.filter = filter_find((char*)value)))
|
if ((arg->value.filter = filter_find((char*)value)))
|
||||||
{
|
{
|
||||||
arg->type = MODULECMD_ARG_FILTER;
|
arg->type.type = MODULECMD_ARG_FILTER;
|
||||||
rval = true;
|
rval = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -316,9 +316,15 @@ static bool process_argument(modulecmd_arg_type_t type, const void* value,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_OUTPUT:
|
||||||
|
arg->type.type = MODULECMD_ARG_OUTPUT;
|
||||||
|
arg->value.dcb = (DCB*)value;
|
||||||
|
rval = true;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ss_dassert(false);
|
ss_dassert(false);
|
||||||
MXS_ERROR("Undefined argument type: %0lx", type);
|
MXS_ERROR("Undefined argument type: %0lx", type->type);
|
||||||
*err = "internal error";
|
*err = "internal error";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -353,7 +359,7 @@ static MODULECMD_ARG* modulecmd_arg_create(int argc)
|
|||||||
|
|
||||||
static void free_argument(struct arg_node *arg)
|
static void free_argument(struct arg_node *arg)
|
||||||
{
|
{
|
||||||
switch (arg->type)
|
switch (arg->type.type)
|
||||||
{
|
{
|
||||||
case MODULECMD_ARG_STRING:
|
case MODULECMD_ARG_STRING:
|
||||||
MXS_FREE(arg->value.string);
|
MXS_FREE(arg->value.string);
|
||||||
@ -451,7 +457,7 @@ MODULECMD_ARG* modulecmd_arg_parse(const MODULECMD *cmd, int argc, const void **
|
|||||||
{
|
{
|
||||||
const char *err = "";
|
const char *err = "";
|
||||||
|
|
||||||
if (!process_argument(cmd->arg_types[i], argv[i], &arg->argv[i], &err))
|
if (!process_argument(&cmd->arg_types[i], argv[i], &arg->argv[i], &err))
|
||||||
{
|
{
|
||||||
error = true;
|
error = true;
|
||||||
modulecmd_set_error("Argument %d, %s: %s", i + 1, err, argv[i] ? argv[i] : "No argument given");
|
modulecmd_set_error("Argument %d, %s: %s", i + 1, err, argv[i] ? argv[i] : "No argument given");
|
||||||
@ -580,3 +586,82 @@ bool modulecmd_foreach(const char *domain_re, const char *ident_re,
|
|||||||
spinlock_release(&modulecmd_lock);
|
spinlock_release(&modulecmd_lock);
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* modulecmd_argtype_to_str(modulecmd_arg_type_t *type)
|
||||||
|
{
|
||||||
|
const char *strtype = "UNKNOWN";
|
||||||
|
|
||||||
|
switch (MODULECMD_GET_TYPE(type))
|
||||||
|
{
|
||||||
|
case MODULECMD_ARG_NONE:
|
||||||
|
strtype = "NONE";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_STRING:
|
||||||
|
strtype = "STRING";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_BOOLEAN:
|
||||||
|
strtype = "BOOLEAN";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_SERVICE:
|
||||||
|
strtype = "SERVICE";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_SERVER:
|
||||||
|
strtype = "SERVER";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_SESSION:
|
||||||
|
strtype = "SESSION";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_SESSION_PTR:
|
||||||
|
strtype = "SESSION_PTR";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_DCB:
|
||||||
|
strtype = "DCB";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_DCB_PTR:
|
||||||
|
strtype = "DCB_PTR";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_MONITOR:
|
||||||
|
strtype = "MONITOR";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_FILTER:
|
||||||
|
strtype = "FILTER";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULECMD_ARG_OUTPUT:
|
||||||
|
strtype = "OUTPUT";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ss_dassert(false);
|
||||||
|
MXS_ERROR("Unknown type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t slen = strlen(strtype);
|
||||||
|
size_t extra = MODULECMD_ARG_IS_REQUIRED(type) ? 0 : 2;
|
||||||
|
char *rval = MXS_MALLOC(slen + extra + 1);
|
||||||
|
|
||||||
|
if (rval)
|
||||||
|
{
|
||||||
|
const char *fmtstr = extra ? "[%s]" : "%s";
|
||||||
|
sprintf(rval, fmtstr, strtype);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool modulecmd_arg_is_present(const MODULECMD_ARG *arg, int idx)
|
||||||
|
{
|
||||||
|
return arg->argc > idx &&
|
||||||
|
MODULECMD_GET_TYPE(&arg->argv[idx].type) != MODULECMD_ARG_NONE;
|
||||||
|
}
|
||||||
|
@ -47,7 +47,11 @@ int test_arguments()
|
|||||||
|
|
||||||
const char *ns = "test_arguments";
|
const char *ns = "test_arguments";
|
||||||
const char *id = "test_arguments";
|
const char *id = "test_arguments";
|
||||||
modulecmd_arg_type_t args1[] = {MODULECMD_ARG_STRING, MODULECMD_ARG_BOOLEAN};
|
modulecmd_arg_type_t args1[] =
|
||||||
|
{
|
||||||
|
{MODULECMD_ARG_STRING, ""},
|
||||||
|
{MODULECMD_ARG_BOOLEAN, ""}
|
||||||
|
};
|
||||||
|
|
||||||
TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty");
|
TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty");
|
||||||
|
|
||||||
@ -150,8 +154,8 @@ int test_optional_arguments()
|
|||||||
const void *id = "test_optional_arguments";
|
const void *id = "test_optional_arguments";
|
||||||
modulecmd_arg_type_t args1[] =
|
modulecmd_arg_type_t args1[] =
|
||||||
{
|
{
|
||||||
MODULECMD_ARG_STRING | MODULECMD_ARG_OPTIONAL,
|
{MODULECMD_ARG_STRING | MODULECMD_ARG_OPTIONAL, ""},
|
||||||
MODULECMD_ARG_BOOLEAN | MODULECMD_ARG_OPTIONAL
|
{MODULECMD_ARG_BOOLEAN | MODULECMD_ARG_OPTIONAL, ""}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(modulecmd_register_command(ns, id, test_fn2, 2, args1),
|
TEST(modulecmd_register_command(ns, id, test_fn2, 2, args1),
|
||||||
@ -323,8 +327,12 @@ int test_pointers()
|
|||||||
const char *ns = "test_pointers";
|
const char *ns = "test_pointers";
|
||||||
const char *id = "test_pointers";
|
const char *id = "test_pointers";
|
||||||
|
|
||||||
modulecmd_arg_type_t args[] = {MODULECMD_ARG_DCB, MODULECMD_ARG_DCB_PTR,
|
modulecmd_arg_type_t args[] =
|
||||||
MODULECMD_ARG_SESSION, MODULECMD_ARG_SESSION_PTR
|
{
|
||||||
|
{MODULECMD_ARG_DCB, ""},
|
||||||
|
{MODULECMD_ARG_DCB_PTR, ""},
|
||||||
|
{MODULECMD_ARG_SESSION, ""},
|
||||||
|
{MODULECMD_ARG_SESSION_PTR, ""}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(modulecmd_register_command(ns, id, ptrfn, 4, args), "Registering a command should succeed");
|
TEST(modulecmd_register_command(ns, id, ptrfn, 4, args), "Registering a command should succeed");
|
||||||
|
Reference in New Issue
Block a user