summaryrefslogtreecommitdiffstats
path: root/source3/utils
diff options
context:
space:
mode:
authorChris Davis <cd.rattan@gmail.com>2014-07-31 23:24:19 -0700
committerMichael Adam <obnox@samba.org>2014-10-01 14:32:09 +0200
commitbcab659516382d5dc51b1558a895a9a26d81c6b8 (patch)
tree3fd5eedf3128d2731e114913388a0419ca237a90 /source3/utils
parent09245177a4031fb1a1319071e745f0df10b1ee53 (diff)
downloadsamba-bcab659516382d5dc51b1558a895a9a26d81c6b8.tar.gz
samba-bcab659516382d5dc51b1558a895a9a26d81c6b8.tar.xz
samba-bcab659516382d5dc51b1558a895a9a26d81c6b8.zip
regedit: search values and repeat search from cursor positions
Recovering the search position from the cursors is safer than retaining a pointer to the last node, as the pointer will become invalid if the user deletes the item or refreshes the cache. Signed-off-by: Chris Davis <cd.rattan@gmail.com> Reviewed-by: Andreas Schneider <asn@samba.org> Reviewed-by: Michael Adam <obnox@samba.org>
Diffstat (limited to 'source3/utils')
-rw-r--r--source3/utils/regedit.c186
-rw-r--r--source3/utils/regedit.h1
-rw-r--r--source3/utils/regedit_treeview.c47
-rw-r--r--source3/utils/regedit_treeview.h1
-rw-r--r--source3/utils/regedit_valuelist.c100
-rw-r--r--source3/utils/regedit_valuelist.h13
6 files changed, 265 insertions, 83 deletions
diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c
index c1b94ac9d5..a5fb913e5d 100644
--- a/source3/utils/regedit.c
+++ b/source3/utils/regedit.c
@@ -208,57 +208,19 @@ static void add_reg_key(struct regedit *regedit, struct tree_node *node,
}
}
-static WERROR next_depth_first(struct tree_node **node)
-{
- WERROR rv = WERR_OK;
-
- SMB_ASSERT(node != NULL && *node != NULL);
-
- if (tree_node_has_children(*node)) {
- /* 1. If the node has children, go to the first one. */
- rv = tree_node_load_children(*node);
- if (W_ERROR_IS_OK(rv)) {
- SMB_ASSERT((*node)->child_head != NULL);
- *node = (*node)->child_head;
- }
- } else if ((*node)->next) {
- /* 2. If there's a node directly after this one, go there */
- *node = (*node)->next;
- } else {
- /* 3. Otherwise, go up the hierarchy to find the next one */
- do {
- *node = (*node)->parent;
- if (*node && (*node)->next) {
- *node = (*node)->next;
- break;
- }
- } while (*node);
- }
-
- return rv;
-}
-
-static WERROR regedit_search_next(struct regedit *regedit)
-{
- WERROR rv;
- struct regedit_search_opts *opts = &regedit->active_search;
-
- if (opts->search_recursive) {
- rv = next_depth_first(&opts->node);
- if (!W_ERROR_IS_OK(rv)) {
- return rv;
- }
- } else {
- opts->node = opts->node->next;
- }
-
- return WERR_OK;
-}
-
-static WERROR regedit_search(struct regedit *regedit)
+enum search_flags {
+ SEARCH_NEXT = (1<<0),
+ SEARCH_PREV = (1<<1),
+ SEARCH_REPEAT = (1<<2)
+};
+static WERROR regedit_search(struct regedit *regedit, struct tree_node *node,
+ struct value_item *vitem, unsigned flags)
{
struct regedit_search_opts *opts;
struct tree_node *found;
+ struct value_item *found_value;
+ bool search_key, need_sync;
+ char *save_value_name;
WERROR rv;
opts = &regedit->active_search;
@@ -269,25 +231,73 @@ static WERROR regedit_search(struct regedit *regedit)
SMB_ASSERT(opts->search_key || opts->search_value);
- for (found = NULL; opts->node && !found; ) {
- if (opts->search_key &&
- opts->match(opts->node->name, opts->query)) {
- found = opts->node;
+ rv = WERR_OK;
+ found = NULL;
+ found_value = NULL;
+ save_value_name = NULL;
+ search_key = opts->search_key;
+ need_sync = false;
+
+ if (opts->search_value) {
+ struct value_item *it;
+
+ it = value_list_get_current_item(regedit->vl);
+ if (it) {
+ save_value_name = talloc_strdup(regedit,
+ it->value_name);
+ if (save_value_name == NULL) {
+ return WERR_NOMEM;
+ }
}
+
+ if (vitem) {
+ search_key = false;
+ }
+ }
+
+ if (!vitem && (flags & SEARCH_REPEAT)) {
if (opts->search_value) {
- /* TODO
- rv = regedit_search_value(regedit);
- if (W_ERROR_IS_OK(rv)) {
- found = opts->node;
- } else if (!W_ERROR_EQUAL(rv, WERR_NO_MORE_ITEMS)) {
- return rv;
+ search_key = false;
+ } else if (!tree_node_next(&node, opts->search_recursive, &rv)) {
+ beep();
+ return rv;
+ }
+ }
+
+ do {
+ if (search_key) {
+ SMB_ASSERT(opts->search_key == true);
+ if (opts->match(node->name, opts->query)) {
+ found = node;
+ } else if (opts->search_value) {
+ search_key = false;
}
- */
}
- rv = regedit_search_next(regedit);
- if (!W_ERROR_IS_OK(rv)) {
- return rv;
+ if (!search_key) {
+ SMB_ASSERT(opts->search_value == true);
+ if (!vitem) {
+ rv = value_list_load_quick(regedit->vl,
+ node->key);
+ if (!W_ERROR_IS_OK(rv)) {
+ goto out;
+ }
+ need_sync = true;
+ }
+ found_value = value_list_find_next_item(regedit->vl,
+ vitem,
+ opts->query,
+ opts->match);
+ if (found_value) {
+ found = node;
+ } else {
+ vitem = NULL;
+ search_key = opts->search_key;
+ }
}
+ } while (!found && tree_node_next(&node, opts->search_recursive, &rv));
+
+ if (!W_ERROR_IS_OK(rv)) {
+ goto out;
}
if (found) {
@@ -298,14 +308,51 @@ static WERROR regedit_search(struct regedit *regedit)
print_path(regedit, found);
}
tree_view_set_current_node(regedit->keys, found);
- load_values(regedit);
+ if (found_value) {
+ if (need_sync) {
+ value_list_sync(regedit->vl);
+ }
+ value_list_set_current_item(regedit->vl, found_value);
+ regedit->tree_input = false;
+ } else {
+ load_values(regedit);
+ regedit->tree_input = true;
+ }
tree_view_show(regedit->keys);
value_list_show(regedit->vl);
+ print_heading(regedit);
} else {
+ if (need_sync) {
+ load_values(regedit);
+ value_list_set_current_item_by_name(regedit->vl,
+ save_value_name);
+ }
beep();
}
- return WERR_OK;
+out:
+ talloc_free(save_value_name);
+
+ return rv;
+}
+
+static void regedit_search_repeat(struct regedit *regedit, unsigned flags)
+{
+ struct tree_node *node;
+ struct value_item *vitem;
+ struct regedit_search_opts *opts;
+
+ opts = &regedit->active_search;
+ if (opts->query == NULL) {
+ return;
+ }
+
+ node = tree_view_get_current_node(regedit->keys);
+ vitem = NULL;
+ if (opts->search_value && !regedit->tree_input) {
+ vitem = value_list_get_current_item(regedit->vl);
+ }
+ regedit_search(regedit, node, vitem, flags | SEARCH_REPEAT);
}
static void handle_tree_input(struct regedit *regedit, int c)
@@ -535,27 +582,28 @@ static void handle_main_input(struct regedit *regedit, int c)
case '/': {
int rv;
struct regedit_search_opts *opts;
+ struct tree_node *node;
opts = &regedit->active_search;
rv = dialog_search_input(regedit, opts);
if (rv == DIALOG_OK) {
SMB_ASSERT(opts->query != NULL);
opts->match = find_substring_nocase;
- opts->node = regedit->keys->root;
+ node = regedit->keys->root;
if (opts->search_case) {
opts->match = find_substring;
}
if (!opts->search_recursive) {
- opts->node =
- tree_view_get_current_node(regedit->keys);
+ node = tree_view_get_current_node(regedit->keys);
+ node = tree_node_first(node);
}
- regedit_search(regedit);
+ regedit_search(regedit, node, NULL, SEARCH_NEXT);
}
break;
}
case 'x':
case 'X':
- regedit_search(regedit);
+ regedit_search_repeat(regedit, SEARCH_NEXT);
break;
case '\t':
regedit->tree_input = !regedit->tree_input;
diff --git a/source3/utils/regedit.h b/source3/utils/regedit.h
index c99aebab97..0928f9ea9b 100644
--- a/source3/utils/regedit.h
+++ b/source3/utils/regedit.h
@@ -64,7 +64,6 @@ typedef bool (*regedit_search_match_fn_t)(const char *, const char *);
struct regedit_search_opts {
const char *query;
regedit_search_match_fn_t match;
- struct tree_node *node;
bool search_key;
bool search_value;
bool search_recursive;
diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c
index 885e6d0998..cf071de3d8 100644
--- a/source3/utils/regedit_treeview.c
+++ b/source3/utils/regedit_treeview.c
@@ -312,6 +312,53 @@ finish:
return rv;
}
+static WERROR next_depth_first(struct tree_node **node)
+{
+ WERROR rv = WERR_OK;
+
+ SMB_ASSERT(node != NULL && *node != NULL);
+
+ if (tree_node_has_children(*node)) {
+ /* 1. If the node has children, go to the first one. */
+ rv = tree_node_load_children(*node);
+ if (W_ERROR_IS_OK(rv)) {
+ SMB_ASSERT((*node)->child_head != NULL);
+ *node = (*node)->child_head;
+ }
+ } else if ((*node)->next) {
+ /* 2. If there's a node directly after this one, go there */
+ *node = (*node)->next;
+ } else {
+ /* 3. Otherwise, go up the hierarchy to find the next one */
+ do {
+ *node = (*node)->parent;
+ if (*node && (*node)->next) {
+ *node = (*node)->next;
+ break;
+ }
+ } while (*node);
+ }
+
+ return rv;
+}
+
+bool tree_node_next(struct tree_node **node, bool depth, WERROR *err)
+{
+ *err = WERR_OK;
+
+ if (*node == NULL) {
+ return false;
+ }
+
+ if (depth) {
+ *err = next_depth_first(node);
+ } else {
+ *node = (*node)->next;
+ }
+
+ return *node != NULL && W_ERROR_IS_OK(*err);
+}
+
void tree_view_clear(struct tree_view *view)
{
multilist_set_data(view->list, NULL);
diff --git a/source3/utils/regedit_treeview.h b/source3/utils/regedit_treeview.h
index 919507f9e2..ba0cd0a8ae 100644
--- a/source3/utils/regedit_treeview.h
+++ b/source3/utils/regedit_treeview.h
@@ -60,6 +60,7 @@ void tree_node_append(struct tree_node *left, struct tree_node *right);
struct tree_node *tree_node_pop(struct tree_node **plist);
struct tree_node *tree_node_first(struct tree_node *list);
struct tree_node *tree_node_last(struct tree_node *list);
+bool tree_node_next(struct tree_node **node, bool depth, WERROR *err);
void tree_node_append_last(struct tree_node *list, struct tree_node *node);
size_t tree_node_print_path(WINDOW *label, struct tree_node *node);
const char **tree_node_get_path(TALLOC_CTX *ctx, struct tree_node *node);
diff --git a/source3/utils/regedit_valuelist.c b/source3/utils/regedit_valuelist.c
index aa387a740a..f12a81ebd2 100644
--- a/source3/utils/regedit_valuelist.c
+++ b/source3/utils/regedit_valuelist.c
@@ -17,6 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "includes.h"
+#include "regedit.h"
#include "regedit_valuelist.h"
#include "regedit_list.h"
#include "lib/registry/registry.h"
@@ -335,7 +337,8 @@ static int vitem_cmp(struct value_item *a, struct value_item *b)
return strcmp(a->value_name, b->value_name);
}
-WERROR value_list_load(struct value_list *vl, struct registry_key *key)
+/* load only the value names into memory to enable searching */
+WERROR value_list_load_quick(struct value_list *vl, struct registry_key *key)
{
uint32_t nvalues;
uint32_t idx;
@@ -366,18 +369,28 @@ WERROR value_list_load(struct value_list *vl, struct registry_key *key)
talloc_free(new_items);
return rv;
}
+ }
+
+ TYPESAFE_QSORT(new_items, nvalues, vitem_cmp);
+ vl->nvalues = nvalues;
+ vl->values = new_items;
- rv = append_data_summary(new_items, vitem);
+ return rv;
+}
+
+/* sync up the UI with the list */
+WERROR value_list_sync(struct value_list *vl)
+{
+ uint32_t idx;
+ WERROR rv;
+
+ for (idx = 0; idx < vl->nvalues; ++idx) {
+ rv = append_data_summary(vl->values, &vl->values[idx]);
if (!W_ERROR_IS_OK(rv)) {
- talloc_free(new_items);
return rv;
}
}
- TYPESAFE_QSORT(new_items, nvalues, vitem_cmp);
-
- vl->nvalues = nvalues;
- vl->values = new_items;
rv = multilist_set_data(vl->list, vl);
if (W_ERROR_IS_OK(rv)) {
multilist_refresh(vl->list);
@@ -386,6 +399,72 @@ WERROR value_list_load(struct value_list *vl, struct registry_key *key)
return rv;
}
+WERROR value_list_load(struct value_list *vl, struct registry_key *key)
+{
+ WERROR rv;
+
+ rv = value_list_load_quick(vl, key);
+ if (!W_ERROR_IS_OK(rv)) {
+ return rv;
+ }
+
+ rv = value_list_sync(vl);
+
+ return rv;
+}
+
+struct value_item *value_list_find_next_item(struct value_list *vl,
+ struct value_item *vitem,
+ const char *s,
+ regedit_search_match_fn_t match)
+{
+ struct value_item *end;
+
+ if (!vl->values) {
+ return NULL;
+ }
+
+ if (vitem) {
+ ++vitem;
+ } else {
+ vitem = &vl->values[0];
+ }
+
+ for (end = &vl->values[vl->nvalues]; vitem < end; ++vitem) {
+ if (match(vitem->value_name, s)) {
+ return vitem;
+ }
+ }
+
+ return NULL;
+}
+
+struct value_item *value_list_find_prev_item(struct value_list *vl,
+ struct value_item *vitem,
+ const char *s,
+ regedit_search_match_fn_t match)
+{
+ struct value_item *end;
+
+ if (!vl->values) {
+ return NULL;
+ }
+
+ if (vitem) {
+ --vitem;
+ } else {
+ vitem = &vl->values[vl->nvalues - 1];
+ }
+
+ for (end = &vl->values[-1]; vitem > end; --vitem) {
+ if (match(vitem->value_name, s)) {
+ return vitem;
+ }
+ }
+
+ return NULL;
+}
+
struct value_item *value_list_get_current_item(struct value_list *vl)
{
return discard_const_p(struct value_item,
@@ -396,16 +475,13 @@ void value_list_set_current_item_by_name(struct value_list *vl,
const char *name)
{
size_t i;
- struct value_item *item = NULL;
for (i = 0; i < vl->nvalues; ++i) {
if (strequal(vl->values[i].value_name, name)) {
- item = &vl->values[i];
- break;
+ multilist_set_current_row(vl->list, &vl->values[i]);
+ return;
}
}
-
- multilist_set_current_row(vl->list, item);
}
void value_list_set_current_item(struct value_list *vl,
diff --git a/source3/utils/regedit_valuelist.h b/source3/utils/regedit_valuelist.h
index b84b4ff4e4..11783899ff 100644
--- a/source3/utils/regedit_valuelist.h
+++ b/source3/utils/regedit_valuelist.h
@@ -20,7 +20,6 @@
#ifndef _REGEDIT_VALUELIST_H_
#define _REGEDIT_VALUELIST_H_
-#include "includes.h"
#include <ncurses.h>
#include <panel.h>
@@ -48,6 +47,7 @@ struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols,
int begin_y, int begin_x);
void value_list_show(struct value_list *vl);
void value_list_set_selected(struct value_list *vl, bool select);
+const char **value_list_load_names(TALLOC_CTX *ctx, struct registry_key *key);
WERROR value_list_load(struct value_list *vl, struct registry_key *key);
void value_list_resize(struct value_list *vl, int nlines, int ncols,
int begin_y, int begin_x);
@@ -58,4 +58,15 @@ void value_list_set_current_item_by_name(struct value_list *vl,
const char *name);
void value_list_driver(struct value_list *vl, int c);
+WERROR value_list_load_quick(struct value_list *vl, struct registry_key *key);
+WERROR value_list_sync(struct value_list *vl);
+struct value_item *value_list_find_next_item(struct value_list *vl,
+ struct value_item *vitem,
+ const char *s,
+ regedit_search_match_fn_t match);
+struct value_item *value_list_find_prev_item(struct value_list *vl,
+ struct value_item *vitem,
+ const char *s,
+ regedit_search_match_fn_t match);
+
#endif