From ddd54d7b8dfe6ae8593a3ddfce851b6b84cff8d4 Mon Sep 17 00:00:00 2001 From: Muhassina Date: Mon, 23 Dec 2024 14:42:58 +0530 Subject: [PATCH] Adding Collapse functionality in CLI interface --- inc/em_base.h | 9 + inc/em_cli.h | 24 +- inc/em_cli_apis.h | 10 +- src/cli/em_cli.cpp | 801 +++++++++++++++++++++++++++++---------------- src/cli/main.go | 116 +++++-- 5 files changed, 640 insertions(+), 320 deletions(-) diff --git a/inc/em_base.h b/inc/em_base.h index ac31ded..994400f 100644 --- a/inc/em_base.h +++ b/inc/em_base.h @@ -57,6 +57,7 @@ extern "C" #define EM_TEST_IO_PERM 0666 #define EM_IO_BUFF_SZ 4096 +#define EM_LONG_IO_BUFF_SZ 4096*4 #define EM_MAX_OP_CLASS 48 #define EM_MAX_POLICIES 16 @@ -2826,8 +2827,16 @@ typedef enum { em_network_node_data_type_raw, } em_network_node_data_type_t; +typedef struct { + bool collapsed; + unsigned int orig_node_ctr; + unsigned int node_ctr; + unsigned int node_pos; +} em_node_display_info_t; + typedef struct em_network_node { em_long_string_t key; + em_node_display_info_t display_info; em_network_node_data_type_t type; em_long_string_t value_str; unsigned int value_int; diff --git a/inc/em_cli.h b/inc/em_cli.h index b6b0666..8ac2d66 100644 --- a/inc/em_cli.h +++ b/inc/em_cli.h @@ -24,6 +24,7 @@ class em_cli_t { em_cmd_t& get_command(char *in, size_t in_len); + em_long_string_t m_lib_dbg_file_name; public: em_editor_callback_t m_editor_cb; @@ -35,18 +36,24 @@ class em_cli_t { em_network_node_t *get_network_tree_by_file(const char *file_name); em_network_node_t *get_network_tree(char *buff); - em_network_node_t *get_child_node_at_index(em_network_node_t *node, unsigned int idx); - char *get_formatted_node_scalar_value(em_network_node_t *node); - char *get_formatted_node_array_value(em_network_node_t *node); - em_network_node_data_type_t get_node_type(em_network_node_t *node); - void free_formatted_node_value(char *str); - int get_network_tree_node(cJSON *obj, em_network_node_t *root); + em_network_node_t *clone_network_tree(em_network_node_t *orig_node, em_network_node_t *dis_node, + unsigned int index, bool collapse, unsigned int *node_ctr = NULL); + em_network_node_t *get_node_from_node_ctr(em_network_node_t *tree, unsigned int node_display_ctr); + int get_network_tree_node(cJSON *obj, em_network_node_t *root, unsigned int *node_ctr); + em_network_node_t *get_child_node_at_index(em_network_node_t *node, unsigned int idx); + unsigned int get_node_display_position(em_network_node_t *node); + char *get_formatted_node_scalar_value(em_network_node_t *node); + char *get_formatted_node_array_value(em_network_node_t *node); + em_network_node_data_type_t get_node_type(em_network_node_t *node); + void free_formatted_node_value(char *str); void free_network_tree(em_network_node_t *tree); void free_network_tree_node(em_network_node_t *node); void *network_tree_to_json(em_network_node_t *root); cJSON *network_tree_node_to_json(em_network_node_t *node, cJSON *parent); - void print_network_tree(em_network_node_t *tree); - void print_network_tree_node(em_network_node_t *node, unsigned int *pident); + char *get_network_tree_string(em_network_node_t *tree); + void get_network_tree_node_string(char *str, em_network_node_t *node, unsigned int *pident); + void init_lib_dbg(char *file_name); + void dump_lib_dbg(char *str); em_cli_t(); ~em_cli_t(); @@ -55,3 +62,4 @@ class em_cli_t { em_cli_t *get_cli(); #endif + diff --git a/inc/em_cli_apis.h b/inc/em_cli_apis.h index 8965b8a..bfe58b7 100644 --- a/inc/em_cli_apis.h +++ b/inc/em_cli_apis.h @@ -32,13 +32,21 @@ const char *get_next_cmd_str(const char *cmd); em_network_node_t *get_network_tree_by_file(const char *file_name); em_network_node_t *get_network_tree(char *buff); em_network_node_t *get_child_node_at_index(em_network_node_t *node, unsigned int idx); +unsigned int get_node_display_position(em_network_node_t *node); char *get_formatted_node_scalar_value(em_network_node_t *node); char *get_formatted_node_array_value(em_network_node_t *node); void free_formatted_node_value(char *str); em_network_node_data_type_t get_node_type(em_network_node_t *node); void free_network_tree(em_network_node_t *node); void *network_tree_to_json(em_network_node_t *node); -void print_network_tree(em_network_node_t *node); +em_network_node_t *clone_network_tree(em_network_node_t *orig_node, em_network_node_t *dis_node, unsigned int index, bool collapse); +char *get_network_tree_string(em_network_node_t *node); +em_network_node_t *get_node_from_node_ctr(em_network_node_t *tree, unsigned int node_display_ctr); +unsigned int can_collapse_node(em_network_node_t *node); +unsigned int can_expand_node(em_network_node_t *node); +void free_network_tree_string(char *str); +void init_lib_dbg(char *file_name); +void dump_lib_dbg(char *fmt); #ifdef __cplusplus } // extern "C" diff --git a/src/cli/em_cli.cpp b/src/cli/em_cli.cpp index ca62437..cf614c2 100644 --- a/src/cli/em_cli.cpp +++ b/src/cli/em_cli.cpp @@ -75,7 +75,7 @@ char *em_cli_t::get_formatted_node_array_value(em_network_node_t *node) } else { snprintf(tmp_str, sizeof(em_short_string_t), "%d, ", node->child[i]->value_int); } - strncat(str, tmp_str, strlen(tmp_str)); + strncat(str, tmp_str, strlen(tmp_str)); } str[strlen(str) - 2] = ']'; @@ -131,340 +131,477 @@ char *em_cli_t::get_formatted_node_scalar_value(em_network_node_t *node) } -void em_cli_t::print_network_tree_node(em_network_node_t *node, unsigned int *pident) -{ - unsigned int i, ident = 0; - em_long_string_t fmt = {0}; - em_long_string_t value_str = {0}; - em_short_string_t tmp_str; - - ident = *pident; - ident++; - *pident = ident; - - for (i = 0; i < ident; i++) { - strncat(fmt, " ", strlen(" ")); - } - - switch (node->type) { - case em_network_node_data_type_invalid: - break; - - case em_network_node_data_type_false: - printf("%s%s:\tfalse\n", fmt, node->key); - break; - - case em_network_node_data_type_true: - printf("%s%s:\ttrue\n", fmt, node->key); - break; - - case em_network_node_data_type_null: - break; - - case em_network_node_data_type_number: - printf("%s%s:\t%d\n", fmt, node->key, node->value_int); - break; - - case em_network_node_data_type_string: - printf("%s%s:\t%s\n", fmt, node->key, node->value_str); - break; - - case em_network_node_data_type_array: - printf("%s%s:", fmt, node->key); - if ((node->num_children > 0) && ((node->child[0]->type == em_network_node_data_type_array) || - (node->child[0]->type == em_network_node_data_type_obj))) { - printf("\n"); - } else if (node->num_children == 0) { - //printf("\n"); - } - break; - - case em_network_node_data_type_obj: - if (node->key[0] != 0) { - printf("%s%s\t\n", fmt, node->key); - } - break; - - case em_network_node_data_type_raw: - break; - - } - - if ((node->type == em_network_node_data_type_array) && (node->num_children > 0) && - ((node->child[0]->type == em_network_node_data_type_number) || - (node->child[0]->type == em_network_node_data_type_string))) { - - snprintf(value_str, sizeof(em_long_string_t), "["); - for (i = 0; i < node->num_children; i++) { - if (node->child[0]->type == em_network_node_data_type_string) { - snprintf(tmp_str, sizeof(em_short_string_t), "%s, ", node->child[i]->value_str); - } else { - snprintf(tmp_str, sizeof(em_short_string_t), "%d, ", node->child[i]->value_int); - } - strncat(value_str, tmp_str, strlen(tmp_str)); - } - - value_str[strlen(value_str) - 2] = ']'; - printf("%s\n", value_str); - } else { - - if (node->type == em_network_node_data_type_array) { - if (node->num_children == 0) { - printf("["); - } else { - snprintf(value_str, sizeof(value_str), "%s[", fmt); - printf("%s\n", value_str); - } - } else if (node->type == em_network_node_data_type_obj) { - if (node->num_children == 0) { - printf("{"); - } else { - snprintf(value_str, sizeof(value_str), "%s{", fmt); - printf("%s\n", value_str); - } - } - - for (i = 0; i < node->num_children; i++) { - print_network_tree_node(node->child[i], pident); - } - if (node->type == em_network_node_data_type_array) { - if (node->num_children == 0) { - printf("]\n"); - } else { - snprintf(value_str, sizeof(value_str), "%s]", fmt); - printf("%s\n", value_str); - } - } else if (node->type == em_network_node_data_type_obj) { - if (node->num_children == 0) { - printf("}\n"); - } else { - snprintf(value_str, sizeof(value_str), "%s}", fmt); - printf("%s\n", value_str); - } - - } - } - - ident = *pident; - ident--; - *pident = ident; -} - -void em_cli_t::print_network_tree(em_network_node_t *node) -{ - unsigned int ident = 0; - - print_network_tree_node(node, &ident); +void em_cli_t::get_network_tree_node_string(char *str, em_network_node_t *node, unsigned int *pident) +{ + unsigned int i, ident = 0; + em_long_string_t fmt = {0}; + em_long_string_t string = {0}; + em_long_string_t value_str = {0}; + em_short_string_t tmp_str; + + ident = *pident; + ident++; + *pident = ident; + + for (i = 0; i < ident; i++) { + strncat(fmt, " ", strlen(" ")); + } + + switch (node->type) { + case em_network_node_data_type_invalid: + break; + + case em_network_node_data_type_false: + snprintf(string, sizeof(em_long_string_t), "%s%s:\tfalse\n", fmt, node->key); + break; + + case em_network_node_data_type_true: + snprintf(string, sizeof(em_long_string_t), "%s%s:\ttrue\n", fmt, node->key); + break; + + case em_network_node_data_type_null: + break; + + case em_network_node_data_type_number: + snprintf(string, sizeof(em_long_string_t), "%s%s:\t%d\n", fmt, node->key, node->value_int); + break; + + case em_network_node_data_type_string: + snprintf(string, sizeof(em_long_string_t), "%s%s:\t%s\n", fmt, node->key, node->value_str); + break; + + case em_network_node_data_type_array: + snprintf(string, sizeof(em_long_string_t), "%s%s:", fmt, node->key); + if ((node->num_children > 0) && ((node->child[0]->type == em_network_node_data_type_array) || + (node->child[0]->type == em_network_node_data_type_obj))) { + printf("\n"); + } else if (node->num_children == 0) { + //printf("\n"); + } + break; + + case em_network_node_data_type_obj: + if (node->key[0] != 0) { + snprintf(string, sizeof(em_long_string_t), "%s%s\t\n", fmt, node->key); + } + break; + + case em_network_node_data_type_raw: + break; + + } + + strncat(str, string, strlen(string)); + + if ((node->type == em_network_node_data_type_array) && (node->num_children > 0) && + ((node->child[0]->type == em_network_node_data_type_number) || + (node->child[0]->type == em_network_node_data_type_string))) { + + snprintf(value_str, sizeof(em_long_string_t), "["); + for (i = 0; i < node->num_children; i++) { + if (node->child[0]->type == em_network_node_data_type_string) { + snprintf(tmp_str, sizeof(em_short_string_t), "%s, ", node->child[i]->value_str); + } else { + snprintf(tmp_str, sizeof(em_short_string_t), "%d, ", node->child[i]->value_int); + } + strncat(value_str, tmp_str, strlen(tmp_str)); + } + + value_str[strlen(value_str) - 2] = ']'; + strncat(value_str, "\n", strlen("\n")); + strncat(str, value_str, strlen(value_str)); + } else { + + if (node->type == em_network_node_data_type_array) { + if (node->num_children == 0) { + strncat(str, "[", strlen("[")); + } else { + snprintf(value_str, sizeof(value_str), "%s[\n", fmt); + strncat(str, value_str, strlen(value_str)); + } + } else if (node->type == em_network_node_data_type_obj) { + if (node->num_children == 0) { + strncat(str, "{", strlen("{")); + } else { + snprintf(value_str, sizeof(value_str), "%s{\n", fmt); + strncat(str, value_str, strlen(value_str)); + } + } + + for (i = 0; i < node->num_children; i++) { + get_network_tree_node_string(str, node->child[i], pident); + } + if (node->type == em_network_node_data_type_array) { + if (node->num_children == 0) { + strncat(str, "]\n", strlen("]\n")); + } else { + snprintf(value_str, sizeof(value_str), "%s]\n", fmt); + strncat(str, value_str, strlen(value_str)); + } + } else if (node->type == em_network_node_data_type_obj) { + if (node->num_children == 0) { + strncat(str, "}\n", strlen("}\n")); + } else { + snprintf(value_str, sizeof(value_str), "%s}\n", fmt); + strncat(str, value_str, strlen(value_str)); + } + + } + } + + ident = *pident; + ident--; + *pident = ident; +} + +char *em_cli_t::get_network_tree_string(em_network_node_t *node) +{ + unsigned int ident = 0; + unsigned int size = EM_LONG_IO_BUFF_SZ; + char *str; + + str = (char *)malloc(size); + memset(str, 0, size); + + get_network_tree_node_string(str, node, &ident); + + return str; } cJSON *em_cli_t::network_tree_node_to_json(em_network_node_t *node, cJSON *parent) { - unsigned int i; - cJSON *obj; + unsigned int i; + cJSON *obj; - switch (node->type) { - case em_network_node_data_type_invalid: - break; + switch (node->type) { + case em_network_node_data_type_invalid: + break; - case em_network_node_data_type_false: - obj = cJSON_CreateFalse(); - break; + case em_network_node_data_type_false: + obj = cJSON_CreateFalse(); + break; - case em_network_node_data_type_true: - obj = cJSON_CreateTrue(); - break; + case em_network_node_data_type_true: + obj = cJSON_CreateTrue(); + break; - case em_network_node_data_type_null: - obj = cJSON_CreateNull(); - break; + case em_network_node_data_type_null: + obj = cJSON_CreateNull(); + break; - case em_network_node_data_type_number: - obj = cJSON_CreateNumber(node->value_int); - break; + case em_network_node_data_type_number: + obj = cJSON_CreateNumber(node->value_int); + break; - case em_network_node_data_type_string: - obj = cJSON_CreateString(node->value_str); - break; + case em_network_node_data_type_string: + obj = cJSON_CreateString(node->value_str); + break; - case em_network_node_data_type_array: - obj = cJSON_CreateArray(); - break; + case em_network_node_data_type_array: + obj = cJSON_CreateArray(); + break; - case em_network_node_data_type_obj: - obj = cJSON_CreateObject(); - break; + case em_network_node_data_type_obj: + obj = cJSON_CreateObject(); + break; - case em_network_node_data_type_raw: - break; - } + case em_network_node_data_type_raw: + break; + } - if (obj == NULL) { - printf("%s:%d: Failed to allocate JSON object\n"); - return NULL; - } + if (obj == NULL) { + printf("%s:%d: Failed to allocate JSON object\n"); + return NULL; + } - cJSON_AddItemToObject(parent, node->key, obj); + cJSON_AddItemToObject(parent, node->key, obj); for (i = 0; i < node->num_children; i++) { network_tree_node_to_json(node->child[i], obj); } - return obj; - + return obj; + } void *em_cli_t::network_tree_to_json(em_network_node_t *root) { - cJSON *obj; - unsigned int i; - - obj = cJSON_CreateObject(); - if (obj == NULL) { - printf("%s:%d: Failed to allocate JSON object\n"); - return NULL; - } - - for (i = 0; i < root->num_children; i++) { - network_tree_node_to_json(root->child[i], obj); - } - - //printf("%s:%d: %s\n", __func__, __LINE__, cJSON_Print(obj)); - - return obj; -} - -int em_cli_t::get_network_tree_node(cJSON *obj, em_network_node_t *root) -{ - cJSON *child_obj, *tmp_obj; - - if (obj->string != NULL) { - strncpy(root->key, obj->string, strlen(obj->string) + 1); - } - - if (cJSON_IsInvalid(obj) == true) { - root->type = em_network_node_data_type_invalid; - } else if (cJSON_IsString(obj) == true) { - root->type = em_network_node_data_type_string; - strncpy(root->value_str, obj->valuestring, strlen(obj->valuestring) + 1); - } else if (cJSON_IsNumber(obj) == true) { - root->type = em_network_node_data_type_number; - root->value_int = obj->valueint; - } else if (cJSON_IsArray(obj) == true) { - root->type = em_network_node_data_type_array; - } else if (cJSON_IsFalse(obj) == true) { - root->type = em_network_node_data_type_false; - } else if (cJSON_IsTrue(obj) == true) { - root->type = em_network_node_data_type_true; - } else if (cJSON_IsNull(obj) == true) { - root->type = em_network_node_data_type_null; - } else if (cJSON_IsRaw(obj) == true) { - root->type = em_network_node_data_type_raw; - } else if (cJSON_IsObject(obj) == true) { - root->type = em_network_node_data_type_obj; - } - - if (obj->child == NULL) { - root->num_children = 0; - return 0; - } - - child_obj = obj->child; - tmp_obj = child_obj; - - while (tmp_obj != NULL) { - root->child[root->num_children] = (em_network_node_t *)malloc(sizeof(em_network_node_t)); - memset(root->child[root->num_children], 0, sizeof(em_network_node_t)); - get_network_tree_node(tmp_obj, root->child[root->num_children]); - - root->num_children++; - - tmp_obj = tmp_obj->next; - } - - return root->num_children; + cJSON *obj; + unsigned int i; + + obj = cJSON_CreateObject(); + if (obj == NULL) { + printf("%s:%d: Failed to allocate JSON object\n"); + return NULL; + } + + for (i = 0; i < root->num_children; i++) { + network_tree_node_to_json(root->child[i], obj); + } + + //printf("%s:%d: %s\n", __func__, __LINE__, cJSON_Print(obj)); + + return obj; } -em_network_node_t *em_cli_t::get_child_node_at_index(em_network_node_t *node, unsigned int idx) +int em_cli_t::get_network_tree_node(cJSON *obj, em_network_node_t *root, unsigned int *node_display_ctr) { - //printf("%s:%d: Index: %d(%d), node:%p\n", __func__, __LINE__, idx, node->num_children, node->child[idx]); - return node->child[idx]; -} + cJSON *child_obj, *tmp_obj; + + if (obj->string != NULL) { + strncpy(root->key, obj->string, strlen(obj->string) + 1); + } + + if (cJSON_IsInvalid(obj) == true) { + root->type = em_network_node_data_type_invalid; + } else if (cJSON_IsString(obj) == true) { + root->type = em_network_node_data_type_string; + strncpy(root->value_str, obj->valuestring, strlen(obj->valuestring) + 1); + } else if (cJSON_IsNumber(obj) == true) { + root->type = em_network_node_data_type_number; + root->value_int = obj->valueint; + } else if (cJSON_IsArray(obj) == true) { + root->type = em_network_node_data_type_array; + } else if (cJSON_IsFalse(obj) == true) { + root->type = em_network_node_data_type_false; + } else if (cJSON_IsTrue(obj) == true) { + root->type = em_network_node_data_type_true; + } else if (cJSON_IsNull(obj) == true) { + root->type = em_network_node_data_type_null; + } else if (cJSON_IsRaw(obj) == true) { + root->type = em_network_node_data_type_raw; + } else if (cJSON_IsObject(obj) == true) { + root->type = em_network_node_data_type_obj; + } + + if (obj->child == NULL) { + root->num_children = 0; + return 0; + } + + child_obj = obj->child; + tmp_obj = child_obj; + + while (tmp_obj != NULL) { + root->child[root->num_children] = (em_network_node_t *)malloc(sizeof(em_network_node_t)); + memset(root->child[root->num_children], 0, sizeof(em_network_node_t)); + if (cJSON_IsArray(obj) == true) { + if ((cJSON_IsObject(tmp_obj) == true) || (cJSON_IsArray(tmp_obj) == true)) { + (*node_display_ctr)++; + } + } else { + (*node_display_ctr)++; + } + root->child[root->num_children]->display_info.node_ctr = *node_display_ctr; + root->child[root->num_children]->display_info.orig_node_ctr = *node_display_ctr; + root->child[root->num_children]->display_info.node_pos = root->display_info.node_pos + 1; + get_network_tree_node(tmp_obj, root->child[root->num_children], node_display_ctr); + + root->num_children++; + + tmp_obj = tmp_obj->next; + } + return root->num_children; +} em_network_node_t *em_cli_t::get_network_tree(char *buff) { - cJSON *obj = NULL; - em_network_node_t *root; + cJSON *obj = NULL; + em_network_node_t *root; + unsigned int node_display_ctr = 0; + + if ((obj = cJSON_Parse(buff)) == NULL) { + return NULL; + } + + root = (em_network_node_t *)malloc(sizeof(em_network_node_t)); + memset(root, 0, sizeof(em_network_node_t)); + + get_network_tree_node(obj, root, &node_display_ctr); + + cJSON_Delete(obj); - if ((obj = cJSON_Parse(buff)) == NULL) { - return NULL; - } + return root; - root = (em_network_node_t *)malloc(sizeof(em_network_node_t)); - memset(root, 0, sizeof(em_network_node_t)); - get_network_tree_node(obj, root); +} + +em_network_node_t *em_cli_t::get_node_from_node_ctr(em_network_node_t *tree, unsigned int node_display_ctr) +{ + em_network_node_t *node = NULL; + bool found_match = false; + unsigned int i; + em_long_string_t dbg; - cJSON_Delete(obj); + snprintf(dbg, sizeof(em_long_string_t), "Node: %s, Node Counter: %d", tree->key, tree->display_info.node_ctr); + dump_lib_dbg(dbg); + + if (tree->display_info.node_ctr == node_display_ctr) { + return tree; + } else { + for (i = 0; i < tree->num_children; i++) { + if ((node = get_node_from_node_ctr(tree->child[i], node_display_ctr)) != NULL) { + found_match = true; + break; + } + } - return root; + if (found_match == true) { + return node; + } + } + return NULL; +} + +em_network_node_t *em_cli_t::clone_network_tree(em_network_node_t *orig_node, em_network_node_t *dis_node, unsigned int index, bool collapse, unsigned int *node_display_ctr) +{ + em_network_node_t *cloned = NULL, *tree_to_add = NULL; + unsigned int i; + bool should_consider = false; + em_network_node_t *node; + unsigned int start_node_ctr = 0; + + if (node_display_ctr == NULL) { + node_display_ctr = &start_node_ctr; + } + + if (orig_node == NULL) { + return NULL; + } + + if (dis_node == NULL) { + node = orig_node; + } else { + node = dis_node; + } + + cloned = (em_network_node_t *)malloc(sizeof(em_network_node_t)); + memset(cloned, 0, sizeof(em_network_node_t)); + + strncpy(cloned->key, node->key, strlen(node->key) + 1); + memcpy(&cloned->display_info, &node->display_info, sizeof(em_node_display_info_t)); + cloned->display_info.node_ctr = *node_display_ctr; + cloned->display_info.orig_node_ctr = node->display_info.orig_node_ctr; + + cloned->type = node->type; + strncpy(cloned->value_str, node->value_str, strlen(node->value_str) + 1); + cloned->value_int = node->value_int; + + should_consider = (node->display_info.node_ctr == index); + + if (should_consider == true) { + if (collapse == false) { + tree_to_add = get_node_from_node_ctr(orig_node, node->display_info.orig_node_ctr); + dump_lib_dbg(get_network_tree_string(tree_to_add)); + assert(tree_to_add != NULL); + assert(tree_to_add->num_children > 0); + for (i = 0; i < tree_to_add->num_children; i++) { + if (node->type == em_network_node_data_type_array) { + if ((tree_to_add->child[0]->type == em_network_node_data_type_array) || + (tree_to_add->child[0]->type == em_network_node_data_type_obj)) { + (*node_display_ctr)++; + } + } else { + (*node_display_ctr)++; + } + cloned->child[i] = clone_network_tree(orig_node, tree_to_add->child[i], index, collapse, node_display_ctr); + } + cloned->display_info.collapsed = false; + cloned->num_children = tree_to_add->num_children; + + + } else { + if (dis_node->num_children > 0) { + cloned->display_info.collapsed = true; + } + } + + } else { + for (i = 0; i < node->num_children; i++) { + if (node->type == em_network_node_data_type_array) { + if ((node->child[0]->type == em_network_node_data_type_array) || (node->child[0]->type == em_network_node_data_type_obj)) { + (*node_display_ctr)++; + } + } else { + (*node_display_ctr)++; + } + cloned->child[i] = clone_network_tree(orig_node, node->child[i], index, collapse, node_display_ctr); + cloned->num_children++; + } + + } + + return cloned; } em_network_node_t *em_cli_t::get_network_tree_by_file(const char *file_name) { - char buff[EM_IO_BUFF_SZ]; + char buff[EM_IO_BUFF_SZ]; - if (em_cmd_cli_t::load_params_file(file_name, buff) < 0) { - return NULL; - } + if (em_cmd_cli_t::load_params_file(file_name, buff) < 0) { + return NULL; + } - return get_network_tree(buff); + return get_network_tree(buff); } void em_cli_t::free_network_tree_node(em_network_node_t *node) { - unsigned int i; + unsigned int i; - for (i = 0; i < node->num_children; i++) { - free_network_tree_node(node->child[i]); - } + for (i = 0; i < node->num_children; i++) { + free_network_tree_node(node->child[i]); + } - free(node); + free(node); } void em_cli_t::free_network_tree(em_network_node_t *node) { - free_network_tree_node(node); + free_network_tree_node(node); +} + +em_network_node_t *em_cli_t::get_child_node_at_index(em_network_node_t *node, unsigned int idx) +{ + //printf("%s:%d: Index: %d(%d), node:%p\n", __func__, __LINE__, idx, node->num_children, node->child[idx]); + return node->child[idx]; +} + +unsigned int em_cli_t::get_node_display_position(em_network_node_t *node) +{ + return node->display_info.node_pos; } + const char *em_cli_t::get_first_cmd_str() { - return em_cmd_cli_t::m_client_cmd_spec[0].get_cmd_name(); + return em_cmd_cli_t::m_client_cmd_spec[0].get_cmd_name(); } const char *em_cli_t::get_next_cmd_str(const char *cmd) { - unsigned int i = 0; - bool found_match = false; + unsigned int i = 0; + bool found_match = false; - if (cmd == NULL) { - return NULL; - } + if (cmd == NULL) { + return NULL; + } - while (em_cmd_cli_t::m_client_cmd_spec[i].get_type() != em_cmd_type_max) { - if (strncmp(em_cmd_cli_t::m_client_cmd_spec[i].get_cmd_name(), cmd, strlen(cmd)) == 0) { - found_match = true; - break; - } + while (em_cmd_cli_t::m_client_cmd_spec[i].get_type() != em_cmd_type_max) { + if (strncmp(em_cmd_cli_t::m_client_cmd_spec[i].get_cmd_name(), cmd, strlen(cmd)) == 0) { + found_match = true; + break; + } - i++; - } + i++; + } - if ((found_match == true) && (em_cmd_cli_t::m_client_cmd_spec[i + 1].get_type() != em_cmd_type_max)) { - return em_cmd_cli_t::m_client_cmd_spec[i + 1].get_cmd_name(); - } + if ((found_match == true) && (em_cmd_cli_t::m_client_cmd_spec[i + 1].get_type() != em_cmd_type_max)) { + return em_cmd_cli_t::m_client_cmd_spec[i + 1].get_cmd_name(); + } - return NULL; + return NULL; } em_cmd_t& em_cli_t::get_command(char *in, size_t in_len) @@ -528,20 +665,20 @@ em_cmd_t& em_cli_t::get_command(char *in, size_t in_len) } if (strncmp(args[num_args - 1], "1", strlen("1")) == 0) { strncat(cmd->m_param.u.args.fixed_args, "Summary@SetAnticipatedChannelPreference", - strlen("Summary@SetAnticipatedChannelPreference")); + strlen("Summary@SetAnticipatedChannelPreference")); } else if (strncmp(args[num_args - 1], "2", strlen("2")) == 0) { strncat(cmd->m_param.u.args.fixed_args, "Summary@ScanChannel", - strlen("Summary@ScanChannel")); - } + strlen("Summary@ScanChannel")); + } break; - case em_cmd_type_get_radio: + case em_cmd_type_get_radio: if ((tmp = strstr(cmd->m_param.u.args.fixed_args, "Summary")) != NULL) { *tmp = 0; } if (strncmp(args[num_args - 1], "1", strlen("1")) == 0) { strncat(cmd->m_param.u.args.fixed_args, "Summary@RadioEnable", - strlen("Summary@RadioEnable")); + strlen("Summary@RadioEnable")); } break; @@ -556,7 +693,7 @@ em_cmd_t& em_cli_t::get_command(char *in, size_t in_len) *tmp = 0; } } - + for (i = 0; i < num_args; i++) { snprintf(cmd->m_param.u.args.args[i], sizeof(cmd->m_param.u.args.args[i]), "%s", args[i]); } @@ -586,14 +723,40 @@ em_network_node_t *em_cli_t::exec(char *in, size_t sz) delete cli_cmd; - return get_network_tree(res); + return get_network_tree(res); +} + +void em_cli_t::init_lib_dbg(char *file_name) +{ + FILE *fp; + + strncpy(m_lib_dbg_file_name, file_name, strlen(file_name) + 1); + if ((fp = fopen(file_name, "w")) == NULL) { + return; + } + + fclose(fp); +} + +void em_cli_t::dump_lib_dbg(char *str) +{ + FILE *fp; + + if ((fp = fopen(m_lib_dbg_file_name, "a")) == NULL) { + return; + } + + fputs("\n==========\n", fp); + fputs(str, fp); + + fclose(fp); } int em_cli_t::init(em_editor_callback_t cb) { - m_editor_cb = cb; + m_editor_cb = cb; - return 0; + return 0; } em_cli_t::em_cli_t() @@ -606,37 +769,37 @@ em_cli_t::~em_cli_t() em_cli_t *get_cli() { - return &g_cli; + return &g_cli; } extern "C" em_network_node_t *exec(char *in, size_t in_len) { - return g_cli.exec(in, in_len); + return g_cli.exec(in, in_len); } - + extern "C" int init(em_editor_callback_t func) { - return g_cli.init(func); + return g_cli.init(func); } extern "C" const char *get_first_cmd_str() { - return g_cli.get_first_cmd_str(); + return g_cli.get_first_cmd_str(); } extern "C" const char *get_next_cmd_str(const char *cmd) { - return g_cli.get_next_cmd_str(cmd); + return g_cli.get_next_cmd_str(cmd); } extern "C" void *get_network_tree_by_file(const char *file_name) { - return g_cli.get_network_tree_by_file(file_name); + return g_cli.get_network_tree_by_file(file_name); } extern "C" void *get_network_tree(char *buff) { - return g_cli.get_network_tree(buff); + return g_cli.get_network_tree(buff); } extern "C" em_network_node_t *get_child_node_at_index(em_network_node_t *node, unsigned int idx) @@ -646,7 +809,7 @@ extern "C" em_network_node_t *get_child_node_at_index(em_network_node_t *node, u extern "C" void free_network_tree(void *node) { - return g_cli.free_network_tree((em_network_node_t *)node); + return g_cli.free_network_tree((em_network_node_t *)node); } extern "C" void *network_tree_to_json(em_network_node_t *node) @@ -654,9 +817,14 @@ extern "C" void *network_tree_to_json(em_network_node_t *node) return g_cli.network_tree_to_json(node); } -extern "C" void print_network_tree(em_network_node_t *node) +extern "C" char *get_network_tree_string(em_network_node_t *node) { - return g_cli.print_network_tree(node); + return g_cli.get_network_tree_string(node); +} + +extern "C" void free_network_tree_string(char *str) +{ + free(str); } extern "C" char *get_formatted_node_scalar_value(em_network_node_t *node) @@ -678,3 +846,56 @@ extern "C" em_network_node_data_type_t get_node_type(em_network_node_t *node) { return g_cli.get_node_type(node); } + +extern "C" unsigned int get_node_display_position(em_network_node_t *node) +{ + return g_cli.get_node_display_position(node); +} + +extern "C" em_network_node_t *get_node_from_node_ctr(em_network_node_t *tree, unsigned int node_display_ctr) +{ + return g_cli.get_node_from_node_ctr(tree, node_display_ctr); +} + +extern "C" em_network_node_t *clone_network_tree(em_network_node_t *orig_node, em_network_node_t *dis_node, unsigned int index, bool collapse) +{ + return g_cli.clone_network_tree(orig_node, dis_node, index, collapse); +} + +extern "C" void init_lib_dbg(char *file_name) +{ + g_cli.init_lib_dbg(file_name); +} + +extern "C" void dump_lib_dbg(char *str) +{ + g_cli.dump_lib_dbg(str); +} + +extern "C" unsigned int can_collapse_node(em_network_node_t *node) +{ + em_long_string_t dbg; + + snprintf(dbg, sizeof(em_long_string_t), "display counter: %d, type: %d, children:%d, node: %s, value:%s\n", + node->display_info.node_ctr, node->type, node->num_children, node->key, node->value_str); + g_cli.dump_lib_dbg(dbg); + + if ((node->type == em_network_node_data_type_obj) || (node->type == em_network_node_data_type_array)) { + if ((node->display_info.collapsed == false) && (node->num_children > 0)) { + return 1; + } + } + + return 0; +} + +extern "C" unsigned int can_expand_node(em_network_node_t *node) +{ + if ((node->type == em_network_node_data_type_obj) || (node->type == em_network_node_data_type_array)) { + if (node->display_info.collapsed == true) { + return 1; + } + } + + return 0; +} diff --git a/src/cli/main.go b/src/cli/main.go index d2bd172..e16b2a9 100644 --- a/src/cli/main.go +++ b/src/cli/main.go @@ -2,18 +2,28 @@ package main /* #cgo CFLAGS: -I../../inc -I../../../OneWifi/include -I../../../OneWifi/source/utils -I../../../halinterface/include -#cgo LDFLAGS: -L../../install/lib -lemcli -lcjson +#cgo LDFLAGS: -L../../install/lib -lemcli -lcjson -lreadline +#include +#include +#include #include "em_cli_apis.h" + +extern int editor_func(em_network_node_t *node); + +static int register_editor_cb() { + return init(editor_func); +} */ import "C" -import ( - "fmt" - "os" - "strings" +import ( + "fmt" + "os" + "strings" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/bubbles/list" + "github.com/charmbracelet/bubbles/list" + "github.com/davecgh/go-spew/spew" tree "github.com/savannahostrowski/tree-bubble" ) @@ -46,7 +56,7 @@ var ( buttonStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("#FFFFFF")). Background(lipgloss.Color("#080563")). - Padding(0, 2). + Padding(0, 1). Width(25). Align(lipgloss.Center) @@ -94,8 +104,11 @@ type model struct { scrollContent []string scrollIndex int activeButton int - currentNode *tree.Node + currentTreeNode *tree.Node + currentNetNode *C.em_network_node_t + displayedNetNode *C.em_network_node_t cursor int + dump *os.File } func newModel() model { @@ -119,9 +132,13 @@ func newModel() model { commandList.SetShowPagination(false) commandList.SetShowHelp(false) + dump, _ := os.OpenFile("messages.log", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644) + C.init_lib_dbg(C.CString("messages_lib.log")) + return model{ list: commandList, statusMessage: "", + dump: dump, } } @@ -130,13 +147,20 @@ func splitIntoLines(content string) []string { } func (m model) Init() tea.Cmd { - return nil + return nil +} + +//export editor_func +func editor_func(*C.em_network_node_t) C.int { + fmt.Println("Inside Go Callnack") + return 0 } func updateNodes(netNode *C.em_network_node_t, treeNode *tree.Node) { var str *C.char - treeNode.Value = C.GoString(&netNode.key[0]) + //treeNode.Value = C.GoString(&netNode.key[0]) + "." + fmt.Sprintf("%d", uint(netNode.display_info.node_ctr)) + "." + fmt.Sprintf("%d", uint(netNode.display_info.orig_node_ctr)) + treeNode.Value = C.GoString(&netNode.key[0]) nodeType := C.get_node_type(netNode) if nodeType == C.em_network_node_data_type_array { @@ -179,7 +203,7 @@ func formatTree(nodes []tree.Node, m *model, cursor *int, currentIdx *int) strin var traverse func(node tree.Node, indent string) traverse = func(node tree.Node, indent string) { // Create a prefix for child nodes - prefix := "├── " + prefix := "[-] " if len(node.Children) == 0 { prefix = "└── " } @@ -191,9 +215,9 @@ func formatTree(nodes []tree.Node, m *model, cursor *int, currentIdx *int) strin // Style node based on selection state var line string if *cursor == idx { - line = fmt.Sprintf("%s%s%s : %s", indent, prefix, activeNodeStyle.Render(node.Value), activeNodeStyle.Render(node.Desc)) + line = fmt.Sprintf("%s%s%s %s", indent, prefix, activeNodeStyle.Render(node.Value), activeNodeStyle.Render(node.Desc)) } else { - line = fmt.Sprintf("%s%s%s : %s", indent, prefix, node.Value, node.Desc) + line = fmt.Sprintf("%s%s%s %s", indent, prefix, node.Value, node.Desc) } builder.WriteString(line + "\n") @@ -215,6 +239,10 @@ func formatTree(nodes []tree.Node, m *model, cursor *int, currentIdx *int) strin func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd + if m.dump != nil { + spew.Fdump(m.dump, msg) + } + switch msg := msg.(type) { case tea.WindowSizeMsg: h, _ := appStyle.GetFrameSize() @@ -225,6 +253,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg.String() { case "tab": m.activeButton = (m.activeButton + 1) % 2 + case "enter": if m.activeButton == 0 && len(m.scrollContent) > 0 { m.statusMessage = "OK Button Pressed" @@ -232,17 +261,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.statusMessage = "Cancel Button Pressed" } else if selectedItem, ok := m.list.SelectedItem().(item); ok { if selectedItem.title == "Set SSID" { - node := C.get_network_tree_by_file(C.CString("NetworkSSID.json")) - if node == nil { + m.currentNetNode = C.get_network_tree_by_file(C.CString("NetworkSSID.json")) + if m.currentNetNode == nil { m.statusMessage = "Error: Failed to retrieve network tree." m.scrollContent = nil } else { - defer C.free_network_tree(node) + treeNode := make([]tree.Node, 1) + m.currentTreeNode = &treeNode[0] + m.displayedNetNode = C.clone_network_tree(m.currentNetNode, nil, 0xffff, false) + updateNodes(m.displayedNetNode, m.currentTreeNode) - treeNode := make([]tree.Node, 1) - updateNodes(node, &treeNode[0]) - - m.currentNode = &treeNode[0] currentIdx := 0 cursor := 0 content := formatTree(treeNode, &m, &cursor, ¤tIdx) @@ -258,14 +286,59 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } } + case "w": if m.scrollIndex > 0 { m.scrollIndex-- } + case "s": if m.scrollIndex < len(m.scrollContent)-1 { m.scrollIndex++ } + + case "c": + netNode := C.get_node_from_node_ctr(m.displayedNetNode, C.uint(m.scrollIndex)) + if uint(C.can_collapse_node(netNode)) == 1 { + tmp := m.displayedNetNode + m.displayedNetNode = C.clone_network_tree(m.currentNetNode, m.displayedNetNode, C.uint(m.scrollIndex), true) + defer C.free_network_tree(tmp); + str := C.get_network_tree_string(m.displayedNetNode) + spew.Fdump(m.dump, "Collapse", m.scrollIndex) + C.dump_lib_dbg(str) + + treeNode := make([]tree.Node, 1) + m.currentTreeNode = &treeNode[0] + updateNodes(m.displayedNetNode, m.currentTreeNode) + + currentIdx := 0 + cursor := 0 + content := formatTree(treeNode, &m, &cursor, ¤tIdx) + m.scrollContent = splitIntoLines(content) + m.scrollIndex = 0 + } + + case "e": + netNode := C.get_node_from_node_ctr(m.displayedNetNode, C.uint(m.scrollIndex)) + if (uint(C.can_expand_node(netNode))) == 1 { + tmp := m.displayedNetNode + m.displayedNetNode = C.clone_network_tree(m.currentNetNode, m.displayedNetNode, C.uint(m.scrollIndex), false) + defer C.free_network_tree(tmp); + str := C.get_network_tree_string(m.displayedNetNode) + spew.Fdump(m.dump, "Expand", m.scrollIndex) + C.dump_lib_dbg(str) + + treeNode := make([]tree.Node, 1) + m.currentTreeNode = &treeNode[0] + updateNodes(m.displayedNetNode, m.currentTreeNode) + + currentIdx := 0 + cursor := 0 + content := formatTree(treeNode, &m, &cursor, ¤tIdx) + m.scrollContent = splitIntoLines(content) + m.scrollIndex = 0 + } + default: newListModel, cmd := m.list.Update(msg) m.list = newListModel @@ -334,7 +407,8 @@ func (m model) View() string { } func main() { - if _, err := tea.NewProgram(newModel(), tea.WithAltScreen()).Run(); err != nil { + + if _, err := tea.NewProgram(newModel(), tea.WithAltScreen()).Run(); err != nil { fmt.Println("Error running program:", err) os.Exit(1) }