aboutsummaryrefslogtreecommitdiffstats
path: root/ctrl/libhicnctrl/src/command.c
blob: 77b6eb7e834e9f032a4521bb0fd0cb0d6d5d731a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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
}