1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

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>
This commit is contained in:
Chris Davis 2014-07-31 23:24:19 -07:00 committed by Michael Adam
parent 09245177a4
commit bcab659516
6 changed files with 266 additions and 84 deletions

View File

@ -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,27 +231,75 @@ 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;
}
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;
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;
}
*/
}
rv = regedit_search_next(regedit);
if (!W_ERROR_IS_OK(rv)) {
if (vitem) {
search_key = false;
}
}
if (!vitem && (flags & SEARCH_REPEAT)) {
if (opts->search_value) {
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;
}
}
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) {
/* Put the cursor on the node that was found */
if (!tree_view_is_node_visible(regedit->keys, 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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
}
rv = append_data_summary(new_items, vitem);
TYPESAFE_QSORT(new_items, nvalues, vitem_cmp);
vl->nvalues = nvalues;
vl->values = new_items;
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,

View File

@ -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