diff options
Diffstat (limited to 'ctrl/libhicnctrl/src/command.c')
-rw-r--r-- | ctrl/libhicnctrl/src/command.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/ctrl/libhicnctrl/src/command.c b/ctrl/libhicnctrl/src/command.c new file mode 100644 index 000000000..77b6eb7e8 --- /dev/null +++ b/ctrl/libhicnctrl/src/command.c @@ -0,0 +1,127 @@ + +/** + * @file command.c + * @brief Implementation of commands. + */ + +#ifdef __linux__ +#define _GNU_SOURCE +#endif /* __linux__ */ +#include <search.h> /* tfind, tdestroy, twalk */ +#include <stdio.h> +#include <ctype.h> +#include <hicn/ctrl/command.h> + +#include <hicn/util/log.h> + +#include <hicn/ctrl/parse.h> + +/* Commands are registered in the following tree. */ +static void *commands_root = NULL; /**< Tree ordered by name */ + +#ifdef __linux__ +static void nothing_to_free() {} + +__attribute__((destructor)) static void command_clear() { + tdestroy(commands_root, nothing_to_free); +} +#endif /* __linux__ */ + +static int _command_compare(const command_parser_t *c1, + const command_parser_t *c2) { + if (c1->object_type != c2->object_type) + return c2->object_type - c1->object_type; + if (c1->action != c2->action) return c2->action - c1->action; + if (c1->nparams != c2->nparams) return c2->nparams - c1->nparams; + return 0; +} + +#define command_compare (int (*)(const void *, const void *))(_command_compare) + +void command_register(const command_parser_t *command) { + // Insert the command in the tree if the keys does not exist yet + tsearch(command, &commands_root, command_compare); +} + +const command_parser_t *command_search(const hc_action_t action, + hc_object_type_t object_type, + unsigned nparams) { + command_parser_t **command, search; + + search.action = action; + search.object_type = object_type; + search.nparams = nparams; + command = tfind(&search, &commands_root, command_compare); + + return command ? *command : NULL; +} + +static inline void to_lowercase(char *p) { + for (; *p; ++p) *p = tolower(*p); +} + +typedef struct { + hc_object_type_t object_type; + hc_action_t action; +} cmd_search_params_t; + +static hc_object_type_t prev_obj = OBJECT_TYPE_UNDEFINED; +static hc_action_t prev_action = ACTION_UNDEFINED; +static void traversal_action(const void *nodep, VISIT which, + void *cmd_params0) { + cmd_search_params_t *cmd_params = cmd_params0; + + // Execute this function during inorder traversal + if (which != postorder && which != leaf) return; + + command_parser_t *datap; + datap = *(command_parser_t **)nodep; + char *obj_str = strdup(object_type_str(datap->object_type)); + to_lowercase(obj_str); + + // List all objects + if (cmd_params->object_type == OBJECT_TYPE_UNDEFINED && + cmd_params->action == ACTION_UNDEFINED) { + if (datap->object_type == prev_obj) goto FREE_STR; + prev_obj = datap->object_type; + + printf("\thelp %s\n", obj_str); + goto FREE_STR; + } + + // List actions for specific object + if (datap->object_type != cmd_params->object_type) goto FREE_STR; + if (cmd_params->action == ACTION_UNDEFINED) { + if (datap->action == prev_action) goto FREE_STR; + prev_action = datap->action; + + printf("\thelp %s %s\n", obj_str, action_to_cmd_action(datap->action)); + goto FREE_STR; + } + + // List commands for specific object and action + if (datap->action != cmd_params->action) goto FREE_STR; + printf(" %s %s ", action_to_cmd_action(datap->action), obj_str); + for (int i = 0; i < datap->nparams; i++) + printf("<%s> ", datap->parameters[i].name); + printf("\n\n"); + // List options' details + if (datap->nparams == 0) goto FREE_STR; + for (int i = 0; i < datap->nparams; i++) + printf("%16s: %s\n", datap->parameters[i].name, datap->parameters[i].help); + printf("\n"); + +FREE_STR: + free(obj_str); +} + +void command_list(hc_object_type_t object_type, hc_action_t action) { +#if defined(__linux__) && !defined(__ANDROID__) + cmd_search_params_t cmd_params = {.object_type = object_type, + .action = action}; + twalk_r(commands_root, traversal_action, &cmd_params); +#else + fprintf(stderr, "twalk_r() function only available on linux"); + (void)traversal_action; +#endif +} |