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:
parent
09245177a4
commit
bcab659516
@ -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 = ®edit->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 = ®edit->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 = ®edit->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 = ®edit->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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user