The Samba-Bugzilla – Attachment 10331 Details for
Bug 10859
Improve samba-regedit
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
v4-2-test patch
regedit.patch (text/plain), 280.81 KB, created by
Andreas Schneider
on 2014-10-09 08:16:26 UTC
(
hide
)
Description:
v4-2-test patch
Filename:
MIME Type:
Creator:
Andreas Schneider
Created:
2014-10-09 08:16:26 UTC
Size:
280.81 KB
patch
obsolete
>From 7ce73452215e68ec78d36b99abc47232f58a5710 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Mon, 4 Aug 2014 21:48:04 -0700 >Subject: [PATCH 01/45] regedit: silence some warnings > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 7e7c649376bd17c7ac9908bbd0ffc235e7cd18f7) >--- > source3/utils/regedit.c | 4 ++-- > source3/utils/regedit.h | 3 ++- > source3/utils/regedit_samba3.c | 4 ++-- > 3 files changed, 6 insertions(+), 5 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 21fd257..a1118d5 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -197,7 +197,7 @@ static void load_values(struct regedit *regedit) > static void add_reg_key(struct regedit *regedit, struct tree_node *node, > bool subkey) > { >- char *name; >+ const char *name; > const char *msg; > > if (!subkey && !node->parent) { >@@ -244,7 +244,7 @@ static void add_reg_key(struct regedit *regedit, struct tree_node *node, > dialog_notice(regedit, DIA_ALERT, "New Key", > "Failed to create key."); > } >- talloc_free(name); >+ talloc_free(discard_const(name)); > } > } > >diff --git a/source3/utils/regedit.h b/source3/utils/regedit.h >index fb9ad61..2ab40f9 100644 >--- a/source3/utils/regedit.h >+++ b/source3/utils/regedit.h >@@ -33,7 +33,8 @@ WERROR reg_openhive_wrap(TALLOC_CTX *ctx, const char *hive, > WERROR reg_openkey_wrap(TALLOC_CTX *ctx, struct samba3_registry_key *parent, > const char *name, struct samba3_registry_key *key); > WERROR reg_enumvalue_wrap(TALLOC_CTX *ctx, struct samba3_registry_key *key, >- uint32 idx, char **name, uint32_t *type, DATA_BLOB *data); >+ uint32 idx, char **name, uint32_t *type, >+ DATA_BLOB *data); > WERROR reg_queryvalue_wrap(TALLOC_CTX *ctx, struct samba3_registry_key *key, > const char *name, uint32_t *type, DATA_BLOB *data); > WERROR reg_enumkey_wrap(TALLOC_CTX *ctx, struct samba3_registry_key *key, >diff --git a/source3/utils/regedit_samba3.c b/source3/utils/regedit_samba3.c >index 39b06bc..4e22be8 100644 >--- a/source3/utils/regedit_samba3.c >+++ b/source3/utils/regedit_samba3.c >@@ -107,7 +107,7 @@ static WERROR samba3_get_value_by_index(TALLOC_CTX *mem_ctx, > mykeydata = talloc_get_type(parent, struct samba3_key); > > return reg_enumvalue_wrap(mem_ctx, &mykeydata->s3key, n, >- value_name, type, data); >+ discard_const(value_name), type, data); > } > > static WERROR samba3_get_value_by_name(TALLOC_CTX *mem_ctx, >@@ -138,7 +138,7 @@ static WERROR samba3_get_subkey_by_index(TALLOC_CTX *mem_ctx, > *keyclass = NULL; > > return reg_enumkey_wrap(mem_ctx, &mykeydata->s3key, n, >- name, last_changed_time); >+ discard_const(name), last_changed_time); > } > > static WERROR samba3_add_key(TALLOC_CTX *mem_ctx, >-- >2.1.1 > > >From 96500ec9db8b9f3501e96f7006734e7092362f69 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Mon, 19 May 2014 11:08:09 -0700 >Subject: [PATCH 02/45] regedit: add white on blue color scheme > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 994f1ed301e2023f0e4c8afa7429388ea90362e1) >--- > source3/utils/regedit.c | 1 + > 1 file changed, 1 insertion(+) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index a1118d5..5e6db7e 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -450,6 +450,7 @@ static void display_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx) > if (colors) { > start_color(); > use_default_colors(); >+ assume_default_colors(COLOR_WHITE, COLOR_BLUE); > } > > regedit = talloc_zero(mem_ctx, struct regedit); >-- >2.1.1 > > >From a6d58234c3dfb5e7d7bf559b770f0b8f9a900790 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Mon, 19 May 2014 17:34:01 -0700 >Subject: [PATCH 03/45] regedit: add padding for key labels when there's not a > prefix. > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit b48f081dc681a0a769165da43668b356c71fdb35) >--- > source3/utils/regedit_treeview.c | 17 +++++++++-------- > 1 file changed, 9 insertions(+), 8 deletions(-) > >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index c74f052..1f2354a 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -253,20 +253,21 @@ WERROR tree_view_update(struct tree_view *view, struct tree_node *list) > } > > for (i = 0, node = list; node != NULL; ++i, node = node->next) { >- const char *label = node->name; >+ char prefix = ' '; > > /* Add a '+' marker to indicate that the item has > descendants. */ > if (tree_node_has_children(node)) { >- SMB_ASSERT(node->label == NULL); >- node->label = talloc_asprintf(node, "+%s", node->name); >- if (node->label == NULL) { >- goto fail; >- } >- label = node->label; >+ prefix = '+'; >+ } >+ >+ SMB_ASSERT(node->label == NULL); >+ node->label = talloc_asprintf(node, "%c%s", prefix, node->name); >+ if (node->label == NULL) { >+ goto fail; > } > >- items[i] = new_item(label, node->name); >+ items[i] = new_item(node->label, node->name); > set_item_userptr(items[i], node); > } > >-- >2.1.1 > > >From cccb802cb3d8a5da5ddae5ae026326d07b6fe0d4 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Tue, 20 May 2014 16:17:42 -0700 >Subject: [PATCH 04/45] regedit: add borders around key and value lists, and > change headings > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit c79837c215de59fa07b665bb79149058f36828d7) >--- > source3/utils/regedit.c | 25 +++++++------------------ > source3/utils/regedit_treeview.c | 32 +++++++++++++++++++++++++++++++- > source3/utils/regedit_treeview.h | 2 ++ > source3/utils/regedit_valuelist.c | 29 ++++++++++++++++++++++++++++- > source3/utils/regedit_valuelist.h | 2 ++ > 5 files changed, 70 insertions(+), 20 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 5e6db7e..86983c2 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -30,14 +30,14 @@ > #include <panel.h> > > #define KEY_START_X 0 >-#define KEY_START_Y 3 >+#define KEY_START_Y 1 > #define KEY_WIDTH (COLS / 4) > #define KEY_HEIGHT (LINES - KEY_START_Y - 2) > #define VAL_START_X KEY_WIDTH >-#define VAL_START_Y 3 >+#define VAL_START_Y 1 > #define VAL_WIDTH (COLS - KEY_WIDTH) > #define VAL_HEIGHT (LINES - VAL_START_Y - 2) >-#define HEADING_START_Y (KEY_START_Y - 1) >+ > #define HELP1_START_Y (LINES - 2) > #define HELP1_START_X 0 > #define HELP1_WIDTH (LINES) >@@ -164,24 +164,13 @@ static void print_help(struct regedit *regedit) > > static void print_heading(struct regedit *regedit) > { >- move(HEADING_START_Y, 0); >- clrtoeol(); >- > if (regedit->tree_input) { >- attron(A_REVERSE); >- } else { >- attroff(A_REVERSE); >- } >- mvprintw(HEADING_START_Y, KEY_START_X, "Key"); >- attroff(A_REVERSE); >- >- if (!regedit->tree_input) { >- attron(A_REVERSE); >+ tree_view_set_selected(regedit->keys, true); >+ value_list_set_selected(regedit->vl, false); > } else { >- attroff(A_REVERSE); >+ tree_view_set_selected(regedit->keys, false); >+ value_list_set_selected(regedit->vl, true); > } >- mvprintw(HEADING_START_Y, VAL_START_X, "Value"); >- attroff(A_REVERSE); > > print_help(regedit); > } >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index 1f2354a..f2241e6 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -20,6 +20,8 @@ > #include "regedit_treeview.h" > #include "lib/registry/registry.h" > >+#define HEADING_X 3 >+ > struct tree_node *tree_node_new(TALLOC_CTX *ctx, struct tree_node *parent, > const char *name, struct registry_key *key) > { >@@ -284,6 +286,16 @@ fail: > return WERR_NOMEM; > } > >+void tree_view_set_selected(struct tree_view *view, bool select) >+{ >+ attr_t attr = A_NORMAL; >+ >+ if (select) { >+ attr = A_REVERSE; >+ } >+ mvwchgat(view->window, 0, HEADING_X, 3, attr, 0, NULL); >+} >+ > void tree_view_show(struct tree_view *view) > { > post_menu(view->menu); >@@ -301,6 +313,9 @@ static int tree_view_free(struct tree_view *view) > if (view->panel) { > del_panel(view->panel); > } >+ if (view->sub) { >+ delwin(view->sub); >+ } > if (view->window) { > delwin(view->window); > } >@@ -332,6 +347,14 @@ struct tree_view *tree_view_new(TALLOC_CTX *ctx, struct tree_node *root, > if (view->window == NULL) { > goto fail; > } >+ view->sub = subwin(view->window, nlines - 2, ncols - 2, >+ begin_y + 1, begin_x + 1); >+ if (view->sub == NULL) { >+ goto fail; >+ } >+ box(view->window, 0, 0); >+ mvwprintw(view->window, 0, HEADING_X, "Key"); >+ > view->panel = new_panel(view->window); > if (view->panel == NULL) { > goto fail; >@@ -344,6 +367,7 @@ struct tree_view *tree_view_new(TALLOC_CTX *ctx, struct tree_node *root, > } > set_menu_format(view->menu, nlines, 1); > set_menu_win(view->menu, view->window); >+ set_menu_sub(view->menu, view->sub); > menu_opts_off(view->menu, O_SHOWDESC); > set_menu_mark(view->menu, "* "); > >@@ -360,15 +384,21 @@ fail: > void tree_view_resize(struct tree_view *view, int nlines, int ncols, > int begin_y, int begin_x) > { >- WINDOW *nwin; >+ WINDOW *nwin, *nsub; > > unpost_menu(view->menu); > nwin = newwin(nlines, ncols, begin_y, begin_x); >+ nsub = subwin(nwin, nlines - 2, ncols - 2, begin_y + 1, begin_x + 1); > replace_panel(view->panel, nwin); >+ delwin(view->sub); > delwin(view->window); > view->window = nwin; >+ view->sub = nsub; >+ box(view->window, 0, 0); >+ mvwprintw(view->window, 0, HEADING_X, "Key"); > set_menu_format(view->menu, nlines, 1); > set_menu_win(view->menu, view->window); >+ set_menu_sub(view->menu, view->sub); > post_menu(view->menu); > } > >diff --git a/source3/utils/regedit_treeview.h b/source3/utils/regedit_treeview.h >index 3931441..66e692e 100644 >--- a/source3/utils/regedit_treeview.h >+++ b/source3/utils/regedit_treeview.h >@@ -43,6 +43,7 @@ struct tree_view { > > struct tree_node *root; > WINDOW *window; >+ WINDOW *sub; > PANEL *panel; > MENU *menu; > ITEM **current_items; >@@ -61,6 +62,7 @@ size_t tree_node_print_path(WINDOW *label, struct tree_node *node); > struct tree_view *tree_view_new(TALLOC_CTX *ctx, struct tree_node *root, > int nlines, int ncols, > int begin_y, int begin_x); >+void tree_view_set_selected(struct tree_view *view, bool select); > void tree_view_resize(struct tree_view *view, int nlines, int ncols, > int begin_y, int begin_x); > void tree_view_show(struct tree_view *view); >diff --git a/source3/utils/regedit_valuelist.c b/source3/utils/regedit_valuelist.c >index b135159..4d56fa6 100644 >--- a/source3/utils/regedit_valuelist.c >+++ b/source3/utils/regedit_valuelist.c >@@ -20,6 +20,8 @@ > #include "regedit_valuelist.h" > #include "lib/registry/registry.h" > >+#define HEADING_X 3 >+ > static void value_list_free_items(ITEM **items) > { > size_t i; >@@ -87,6 +89,14 @@ struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols, > if (vl->window == NULL) { > goto fail; > } >+ vl->sub = subwin(vl->window, nlines - 2, ncols - 2, >+ begin_y + 1, begin_x + 1); >+ if (vl->sub == NULL) { >+ goto fail; >+ } >+ box(vl->window, 0, 0); >+ mvwprintw(vl->window, 0, HEADING_X, "Value"); >+ > vl->panel = new_panel(vl->window); > if (vl->panel == NULL) { > goto fail; >@@ -99,6 +109,7 @@ struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols, > > set_menu_format(vl->menu, nlines, 1); > set_menu_win(vl->menu, vl->window); >+ set_menu_sub(vl->menu, vl->sub); > > menu_opts_on(vl->menu, O_SHOWDESC); > set_menu_mark(vl->menu, "* "); >@@ -111,18 +122,34 @@ fail: > return NULL; > } > >+void value_list_set_selected(struct value_list *vl, bool select) >+{ >+ attr_t attr = A_NORMAL; >+ >+ if (select) { >+ attr = A_REVERSE; >+ } >+ mvwchgat(vl->window, 0, HEADING_X, 5, attr, 0, NULL); >+} >+ > void value_list_resize(struct value_list *vl, int nlines, int ncols, > int begin_y, int begin_x) > { >- WINDOW *nwin; >+ WINDOW *nwin, *nsub; > > unpost_menu(vl->menu); > nwin = newwin(nlines, ncols, begin_y, begin_x); >+ nsub = subwin(nwin, nlines - 2, ncols - 2, begin_y + 1, begin_x + 1); > replace_panel(vl->panel, nwin); >+ delwin(vl->sub); > delwin(vl->window); > vl->window = nwin; >+ vl->sub = nsub; >+ box(vl->window, 0, 0); >+ mvwprintw(vl->window, 0, HEADING_X, "Value"); > set_menu_format(vl->menu, nlines, 1); > set_menu_win(vl->menu, vl->window); >+ set_menu_sub(vl->menu, vl->sub); > post_menu(vl->menu); > } > >diff --git a/source3/utils/regedit_valuelist.h b/source3/utils/regedit_valuelist.h >index d01db51..16b0d50 100644 >--- a/source3/utils/regedit_valuelist.h >+++ b/source3/utils/regedit_valuelist.h >@@ -37,6 +37,7 @@ struct value_item { > > struct value_list { > WINDOW *window; >+ WINDOW *sub; > PANEL *panel; > MENU *menu; > ITEM **items; >@@ -46,6 +47,7 @@ struct value_list { > 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); > 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); >-- >2.1.1 > > >From abe1f7f1f373d3b661022ef994253e3cbcb9f30e Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Wed, 21 May 2014 15:03:50 -0700 >Subject: [PATCH 05/45] regedit: free value list subwindow > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit b5d0eb8ee06908ad8171f71b648c43de6303047b) >--- > source3/utils/regedit_valuelist.c | 3 +++ > 1 file changed, 3 insertions(+) > >diff --git a/source3/utils/regedit_valuelist.c b/source3/utils/regedit_valuelist.c >index 4d56fa6..791a8ca 100644 >--- a/source3/utils/regedit_valuelist.c >+++ b/source3/utils/regedit_valuelist.c >@@ -54,6 +54,9 @@ static int value_list_free(struct value_list *vl) > if (vl->panel) { > del_panel(vl->panel); > } >+ if (vl->sub) { >+ delwin(vl->sub); >+ } > if (vl->window) { > delwin(vl->window); > } >-- >2.1.1 > > >From 5a0a51d2123eedd7d32fa8ee986b0fce4deabb24 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Wed, 21 May 2014 17:08:06 -0700 >Subject: [PATCH 06/45] regedit: sort keys > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit bd8abef327e68cf1c1fc9c2cf6e0b11738971521) >--- > source3/utils/regedit_treeview.c | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index f2241e6..cfcf5f2 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -236,6 +236,16 @@ void tree_view_clear(struct tree_view *view) > view->current_items = NULL; > } > >+static int item_comp(ITEM **a, ITEM **b) >+{ >+ struct tree_node *nodea, *nodeb; >+ >+ nodea = item_userptr(*a); >+ nodeb = item_userptr(*b); >+ >+ return strcmp(nodea->name, nodeb->name); >+} >+ > WERROR tree_view_update(struct tree_view *view, struct tree_node *list) > { > ITEM **items; >@@ -273,6 +283,8 @@ WERROR tree_view_update(struct tree_view *view, struct tree_node *list) > set_item_userptr(items[i], node); > } > >+ TYPESAFE_QSORT(items, n_items, item_comp); >+ > unpost_menu(view->menu); > set_menu_items(view->menu, items); > tree_view_free_current_items(view->current_items); >-- >2.1.1 > > >From 4050476fa01c69b77618d78ad39076ffbf673413 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Thu, 22 May 2014 15:23:52 -0700 >Subject: [PATCH 07/45] regedit: add a color scheme for path and context help > sections > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit b8b83509ca080d48530fbde9b012b9c3eb1c42fe) >--- > source3/utils/regedit.c | 14 +++++++++++--- > 1 file changed, 11 insertions(+), 3 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 86983c2..a69fa6b 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -50,6 +50,9 @@ > #define PATH_WIDTH (COLS - 6) > #define PATH_WIDTH_MAX 1024 > >+#define PAIR_YELLOW_CYAN 1 >+#define PAIR_BLACK_CYAN 2 >+ > struct regedit { > WINDOW *main_window; > WINDOW *path_label; >@@ -73,6 +76,8 @@ static void show_path(struct regedit *regedit) > } > copywin(regedit->path_label, regedit->main_window, 0, start_pad, > PATH_START_Y, start_win, PATH_START_Y, PATH_MAX_Y, false); >+ >+ mvchgat(0, 0, COLS, A_BOLD, PAIR_YELLOW_CYAN, NULL); > } > > static void print_path(struct regedit *regedit, struct tree_node *node) >@@ -147,15 +152,16 @@ static void print_help(struct regedit *regedit) > > move(HELP1_START_Y, HELP1_START_X); > clrtoeol(); >- attron(A_REVERSE); >+ attron(COLOR_PAIR(PAIR_BLACK_CYAN)); > mvaddstr(HELP1_START_Y, HELP1_START_X, help); > pad = COLS - strlen(msg) - strlen(help); > for (i = 0; i < pad; ++i) { > addch(' '); > } >- attron(A_BOLD); >+ attroff(COLOR_PAIR(PAIR_BLACK_CYAN)); >+ attron(COLOR_PAIR(PAIR_YELLOW_CYAN) | A_BOLD); > addstr(msg); >- attroff(A_REVERSE | A_BOLD); >+ attroff(COLOR_PAIR(PAIR_YELLOW_CYAN) | A_BOLD); > > move(HELP2_START_Y, HELP2_START_X); > clrtoeol(); >@@ -440,6 +446,8 @@ static void display_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx) > start_color(); > use_default_colors(); > assume_default_colors(COLOR_WHITE, COLOR_BLUE); >+ init_pair(PAIR_YELLOW_CYAN, COLOR_YELLOW, COLOR_CYAN); >+ init_pair(PAIR_BLACK_CYAN, COLOR_BLACK, COLOR_CYAN); > } > > regedit = talloc_zero(mem_ctx, struct regedit); >-- >2.1.1 > > >From 94708b2d05cefb919e0153d36b9d6b12ec9dbdb0 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Mon, 2 Jun 2014 21:50:01 -0700 >Subject: [PATCH 08/45] regedit: add search feature. > >Open up a search input with '/'. 'x' key gets the next >result. > >This patch also ensures that keys are always sorted, so >that the search order matches the order the keys appear >on screen. > >TODO: > + flesh out search interface > + find previous > + search values > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 0ab07cb8069ae59e45fb0f6016096d30de9b4142) >--- > source3/utils/regedit.c | 150 +++++++++++++++++++++++++++++++++++++-- > source3/utils/regedit.h | 13 ++++ > source3/utils/regedit_dialog.c | 14 ++++ > source3/utils/regedit_dialog.h | 4 ++ > source3/utils/regedit_treeview.c | 134 +++++++++++++++++++++++++--------- > source3/utils/regedit_treeview.h | 4 ++ > 6 files changed, 280 insertions(+), 39 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index a69fa6b..77c254b 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -60,6 +60,7 @@ struct regedit { > struct value_list *vl; > struct tree_view *keys; > bool tree_input; >+ struct regedit_search_opts active_search; > }; > > static struct regedit *regedit_main = NULL; >@@ -141,8 +142,9 @@ static void print_help(struct regedit *regedit) > "[b] Edit binary"; > const char *msg = "KEYS"; > const char *help = khelp; >- const char *genhelp = "[TAB] Switch sections [q] Quit regedit " >- "[UP] List up [DOWN] List down"; >+ const char *genhelp = "[TAB] Switch sections [q] Quit " >+ "[UP] List up [DOWN] List down " >+ "[/] Search [x] Next"; > int i, pad; > > if (!regedit->tree_input) { >@@ -185,7 +187,7 @@ static void load_values(struct regedit *regedit) > { > struct tree_node *node; > >- node = item_userptr(current_item(regedit->keys->menu)); >+ node = tree_view_get_current_node(regedit->keys); > value_list_load(regedit->vl, node->key); > } > >@@ -229,7 +231,7 @@ static void add_reg_key(struct regedit *regedit, struct tree_node *node, > new_node = tree_node_new(parent, parent, > name, new_key); > SMB_ASSERT(new_node); >- tree_node_append_last(list, new_node); >+ tree_node_insert_sorted(list, new_node); > } > > list = tree_node_first(node); >@@ -243,6 +245,106 @@ 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) >+{ >+ struct regedit_search_opts *opts; >+ struct tree_node *found; >+ WERROR rv; >+ >+ opts = ®edit->active_search; >+ >+ if (!opts->query || !opts->match) { >+ return WERR_OK; >+ } >+ >+ 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 = regedit_search_next(regedit); >+ if (!W_ERROR_IS_OK(rv)) { >+ return rv; >+ } >+ } >+ >+ if (found) { >+ /* Put the cursor on the node that was found */ >+ if (!tree_view_is_node_visible(regedit->keys, found)) { >+ tree_view_update(regedit->keys, >+ tree_node_first(found)); >+ print_path(regedit, found); >+ } >+ tree_view_set_current_node(regedit->keys, found); >+ load_values(regedit); >+ tree_view_show(regedit->keys); >+ value_list_show(regedit->vl); >+ } else { >+ beep(); >+ } >+ >+ return WERR_OK; >+} >+ > static void handle_tree_input(struct regedit *regedit, int c) > { > struct tree_node *node; >@@ -394,9 +496,49 @@ static void handle_value_input(struct regedit *regedit, int c) > value_list_show(regedit->vl); > } > >+static bool find_substring(const char *haystack, const char *needle) >+{ >+ return strstr(haystack, needle) != NULL; >+} >+ >+static bool find_substring_nocase(const char *haystack, const char *needle) >+{ >+ return strcasestr(haystack, needle) != NULL; >+} >+ > static void handle_main_input(struct regedit *regedit, int c) > { > switch (c) { >+ case 'f': >+ case 'F': >+ case '/': { >+ int rv; >+ struct regedit_search_opts *opts; >+ >+ opts = ®edit->active_search; >+ if (opts->query) { >+ talloc_free(discard_const(opts->query)); >+ } >+ rv = dialog_search_input(regedit, opts); >+ if (rv == DIALOG_OK) { >+ SMB_ASSERT(opts->query != NULL); >+ opts->match = find_substring; >+ opts->node = regedit->keys->root; >+ if (opts->search_nocase) { >+ opts->match = find_substring_nocase; >+ } >+ if (opts->search_relative) { >+ opts->node = >+ tree_view_get_current_node(regedit->keys); >+ } >+ regedit_search(regedit); >+ } >+ break; >+ } >+ case 'x': >+ case 'X': >+ regedit_search(regedit); >+ break; > case '\t': > regedit->tree_input = !regedit->tree_input; > print_heading(regedit); >diff --git a/source3/utils/regedit.h b/source3/utils/regedit.h >index 2ab40f9..113f226 100644 >--- a/source3/utils/regedit.h >+++ b/source3/utils/regedit.h >@@ -59,4 +59,17 @@ WERROR reg_open_samba3(TALLOC_CTX *mem_ctx, struct registry_context **ctx); > > int regedit_getch(void); > >+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; >+ unsigned int search_key:1; >+ unsigned int search_value:1; >+ unsigned int search_recursive:1; >+ unsigned int search_relative:1; >+ unsigned int search_nocase:1; >+}; >+ > #endif >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index c3dd198..944fcc8 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -1207,3 +1207,17 @@ finish: > > return sel; > } >+ >+int dialog_search_input(TALLOC_CTX *ctx, struct regedit_search_opts *opts) >+{ >+ int rv; >+ // TODO >+ >+ opts->search_key = 1; >+ opts->search_recursive = 1; >+ opts->search_nocase = 1; >+ >+ rv = dialog_input(ctx, &opts->query, "Search", "Query"); >+ >+ return rv; >+} >diff --git a/source3/utils/regedit_dialog.h b/source3/utils/regedit_dialog.h >index 0a0aec8..f57bcd1 100644 >--- a/source3/utils/regedit_dialog.h >+++ b/source3/utils/regedit_dialog.h >@@ -73,4 +73,8 @@ WERROR dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, > > int dialog_select_type(TALLOC_CTX *ctx, int *type); > >+struct regedit_search_opts; >+ >+int dialog_search_input(TALLOC_CTX *ctx, struct regedit_search_opts *opts); >+ > #endif >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index cfcf5f2..ef85754 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -117,7 +117,7 @@ struct tree_node *tree_node_last(struct tree_node *list) > return list; > } > >-bool tree_node_has_children(struct tree_node *node) >+static uint32_t get_num_subkeys(struct tree_node *node) > { > const char *classname; > uint32_t num_subkeys; >@@ -128,20 +128,49 @@ bool tree_node_has_children(struct tree_node *node) > uint32_t max_valbufsize; > WERROR rv; > >- if (node->child_head) { >- return true; >- } >- > rv = reg_key_get_info(node, node->key, &classname, &num_subkeys, > &num_values, &last_change_time, > &max_subkeynamelen, &max_valnamelen, > &max_valbufsize); > > if (W_ERROR_IS_OK(rv)) { >- return num_subkeys != 0; >+ return num_subkeys; >+ } >+ >+ return 0; >+} >+ >+bool tree_node_has_children(struct tree_node *node) >+{ >+ if (node->child_head) { >+ return true; > } > >- return false; >+ return get_num_subkeys(node) > 0; >+} >+ >+static int node_cmp(struct tree_node **a, struct tree_node **b) >+{ >+ return strcmp((*a)->name, (*b)->name); >+} >+ >+void tree_node_insert_sorted(struct tree_node *list, struct tree_node *node) >+{ >+ list = tree_node_first(list); >+ >+ if (node_cmp(&list, &node) >= 0) { >+ tree_node_append(node, list); >+ if (list->parent) { >+ list->parent->child_head = node; >+ } >+ return; >+ } >+ >+ while (list->next && node_cmp(&list->next, &node) < 0) { >+ list = list->next; >+ } >+ >+ tree_node_append(list, node); > } > > WERROR tree_node_load_children(struct tree_node *node) >@@ -149,43 +178,63 @@ WERROR tree_node_load_children(struct tree_node *node) > struct registry_key *key; > const char *key_name, *klass; > NTTIME modified; >- uint32_t i; >+ uint32_t i, nsubkeys; > WERROR rv; >- struct tree_node *new_node, *prev; >+ struct tree_node *prev, **array; > > /* does this node already have it's children loaded? */ > if (node->child_head) > return WERR_OK; > >- for (prev = NULL, i = 0; ; ++i) { >+ nsubkeys = get_num_subkeys(node); >+ if (nsubkeys == 0) >+ return WERR_OK; >+ >+ array = talloc_zero_array(node, struct tree_node *, nsubkeys); >+ if (array == NULL) { >+ return WERR_NOMEM; >+ } >+ >+ for (i = 0; i < nsubkeys; ++i) { > rv = reg_key_get_subkey_by_index(node, node->key, i, > &key_name, &klass, > &modified); > if (!W_ERROR_IS_OK(rv)) { >- if (W_ERROR_EQUAL(rv, WERR_NO_MORE_ITEMS)) { >- break; >- } >- >- return rv; >+ goto finish; > } > > rv = reg_open_key(node, node->key, key_name, &key); > if (!W_ERROR_IS_OK(rv)) { >- return rv; >+ goto finish; > } > >- new_node = tree_node_new(node, node, key_name, key); >- if (new_node == NULL) { >- return WERR_NOMEM; >+ array[i] = tree_node_new(node, node, key_name, key); >+ if (array[i] == NULL) { >+ rv = WERR_NOMEM; >+ goto finish; > } >+ } >+ >+ TYPESAFE_QSORT(array, nsubkeys, node_cmp); >+ >+ for (i = 1, prev = array[0]; i < nsubkeys; ++i) { >+ tree_node_append(prev, array[i]); >+ prev = array[i]; >+ } >+ node->child_head = array[0]; >+ >+ rv = WERR_OK; > >- if (prev) { >- tree_node_append(prev, new_node); >+finish: >+ if (!W_ERROR_IS_OK(rv)) { >+ for (i = 0; i < nsubkeys; ++i) { >+ talloc_free(array[i]); > } >- prev = new_node; >+ node->child_head = NULL; > } >+ talloc_free(array); > >- return WERR_OK; >+ return rv; > } > > void tree_node_free_recursive(struct tree_node *list) >@@ -236,16 +285,6 @@ void tree_view_clear(struct tree_view *view) > view->current_items = NULL; > } > >-static int item_comp(ITEM **a, ITEM **b) >-{ >- struct tree_node *nodea, *nodeb; >- >- nodea = item_userptr(*a); >- nodeb = item_userptr(*b); >- >- return strcmp(nodea->name, nodeb->name); >-} >- > WERROR tree_view_update(struct tree_view *view, struct tree_node *list) > { > ITEM **items; >@@ -283,8 +322,6 @@ WERROR tree_view_update(struct tree_view *view, struct tree_node *list) > set_item_userptr(items[i], node); > } > >- TYPESAFE_QSORT(items, n_items, item_comp); >- > unpost_menu(view->menu); > set_menu_items(view->menu, items); > tree_view_free_current_items(view->current_items); >@@ -298,6 +335,33 @@ fail: > return WERR_NOMEM; > } > >+/* is this node in the current level? */ >+bool tree_view_is_node_visible(struct tree_view *view, struct tree_node *node) >+{ >+ struct tree_node *first; >+ >+ first = item_userptr(view->current_items[0]); >+ >+ return first->parent == node->parent; >+} >+ >+void tree_view_set_current_node(struct tree_view *view, struct tree_node *node) >+{ >+ ITEM **it; >+ >+ for (it = view->current_items; *it; ++it) { >+ if (item_userptr(*it) == node) { >+ set_current_item(view->menu, *it); >+ return; >+ } >+ } >+} >+ >+struct tree_node *tree_view_get_current_node(struct tree_view *view) >+{ >+ return item_userptr(current_item(view->menu)); >+} >+ > void tree_view_set_selected(struct tree_view *view, bool select) > { > attr_t attr = A_NORMAL; >diff --git a/source3/utils/regedit_treeview.h b/source3/utils/regedit_treeview.h >index 66e692e..152ba3c 100644 >--- a/source3/utils/regedit_treeview.h >+++ b/source3/utils/regedit_treeview.h >@@ -70,5 +70,9 @@ void tree_view_clear(struct tree_view *view); > WERROR tree_view_update(struct tree_view *view, struct tree_node *list); > bool tree_node_has_children(struct tree_node *node); > WERROR tree_node_load_children(struct tree_node *node); >+void tree_node_insert_sorted(struct tree_node *list, struct tree_node *node); >+bool tree_view_is_node_visible(struct tree_view *view, struct tree_node *node); >+void tree_view_set_current_node(struct tree_view *view, struct tree_node *node); >+struct tree_node *tree_view_get_current_node(struct tree_view *view); > > #endif >-- >2.1.1 > > >From ac78eeafbfa98f56cb9fa6688e50073e5629b6fd Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Mon, 9 Jun 2014 18:29:56 -0700 >Subject: [PATCH 09/45] regedit: add multicolumn list widget > >Widget works for lists with one or more column(s). >Column headers are optional. > >As a test, the patch also modifies regedit to use the >new widget for viewing registry keys. Valuelist still >needs to be upgraded to use this. > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 7ad75367b2a42225a9f3539172e0b0e320d3a517) >--- > source3/utils/regedit.c | 28 +-- > source3/utils/regedit.h | 4 + > source3/utils/regedit_list.c | 524 +++++++++++++++++++++++++++++++++++++++ > source3/utils/regedit_list.h | 78 ++++++ > source3/utils/regedit_treeview.c | 189 ++++++-------- > source3/utils/regedit_treeview.h | 9 +- > source3/wscript_build | 2 +- > 7 files changed, 703 insertions(+), 131 deletions(-) > create mode 100644 source3/utils/regedit_list.c > create mode 100644 source3/utils/regedit_list.h > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 77c254b..ea9aec8 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -25,6 +25,7 @@ > #include "regedit_treeview.h" > #include "regedit_valuelist.h" > #include "regedit_dialog.h" >+#include "regedit_list.h" > #include <ncurses.h> > #include <menu.h> > #include <panel.h> >@@ -50,9 +51,6 @@ > #define PATH_WIDTH (COLS - 6) > #define PATH_WIDTH_MAX 1024 > >-#define PAIR_YELLOW_CYAN 1 >-#define PAIR_BLACK_CYAN 2 >- > struct regedit { > WINDOW *main_window; > WINDOW *path_label; >@@ -351,17 +349,17 @@ static void handle_tree_input(struct regedit *regedit, int c) > > switch (c) { > case KEY_DOWN: >- menu_driver(regedit->keys->menu, REQ_DOWN_ITEM); >+ tree_view_driver(regedit->keys, ML_CURSOR_DOWN); > load_values(regedit); > break; > case KEY_UP: >- menu_driver(regedit->keys->menu, REQ_UP_ITEM); >+ tree_view_driver(regedit->keys, ML_CURSOR_UP); > load_values(regedit); > break; > case '\n': > case KEY_ENTER: > case KEY_RIGHT: >- node = item_userptr(current_item(regedit->keys->menu)); >+ node = tree_view_get_current_node(regedit->keys); > if (node && tree_node_has_children(node)) { > tree_node_load_children(node); > print_path(regedit, node->child_head); >@@ -370,7 +368,7 @@ static void handle_tree_input(struct regedit *regedit, int c) > } > break; > case KEY_LEFT: >- node = item_userptr(current_item(regedit->keys->menu)); >+ node = tree_view_get_current_node(regedit->keys); > if (node && node->parent) { > print_path(regedit, node->parent); > node = tree_node_first(node->parent); >@@ -380,19 +378,19 @@ static void handle_tree_input(struct regedit *regedit, int c) > break; > case 'n': > case 'N': >- node = item_userptr(current_item(regedit->keys->menu)); >+ node = tree_view_get_current_node(regedit->keys); > add_reg_key(regedit, node, false); > break; > case 's': > case 'S': >- node = item_userptr(current_item(regedit->keys->menu)); >+ node = tree_view_get_current_node(regedit->keys); > add_reg_key(regedit, node, true); > break; > case 'd': > case 'D': { > int sel; > >- node = item_userptr(current_item(regedit->keys->menu)); >+ node = tree_view_get_current_node(regedit->keys); > if (!node->parent) { > break; > } >@@ -451,7 +449,7 @@ static void handle_value_input(struct regedit *regedit, int c) > vitem = item_userptr(current_item(regedit->vl->menu)); > if (vitem) { > struct tree_node *node; >- node = item_userptr(current_item(regedit->keys->menu)); >+ node = tree_view_get_current_node(regedit->keys); > dialog_edit_value(regedit, node->key, vitem->type, > vitem, binmode); > value_list_load(regedit->vl, node->key); >@@ -465,7 +463,7 @@ static void handle_value_input(struct regedit *regedit, int c) > sel = dialog_select_type(regedit, &new_type); > if (sel == DIALOG_OK) { > struct tree_node *node; >- node = item_userptr(current_item(regedit->keys->menu)); >+ node = tree_view_get_current_node(regedit->keys); > dialog_edit_value(regedit, node->key, new_type, NULL, > false); > value_list_load(regedit->vl, node->key); >@@ -483,8 +481,8 @@ static void handle_value_input(struct regedit *regedit, int c) > "Really delete value \"%s\"?", > vitem->value_name); > if (sel == DIALOG_OK) { >- ITEM *it = current_item(regedit->keys->menu); >- struct tree_node *node = item_userptr(it); >+ struct tree_node *node; >+ node = tree_view_get_current_node(regedit->keys); > reg_del_value(regedit, node->key, > vitem->value_name); > value_list_load(regedit->vl, node->key); >@@ -590,6 +588,7 @@ static void display_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx) > assume_default_colors(COLOR_WHITE, COLOR_BLUE); > init_pair(PAIR_YELLOW_CYAN, COLOR_YELLOW, COLOR_CYAN); > init_pair(PAIR_BLACK_CYAN, COLOR_BLACK, COLOR_CYAN); >+ init_pair(PAIR_YELLOW_BLUE, COLOR_YELLOW, COLOR_BLUE); > } > > regedit = talloc_zero(mem_ctx, struct regedit); >@@ -620,7 +619,6 @@ static void display_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx) > print_heading(regedit); > > tree_view_show(regedit->keys); >- menu_driver(regedit->keys->menu, REQ_FIRST_ITEM); > load_values(regedit); > value_list_show(regedit->vl); > >diff --git a/source3/utils/regedit.h b/source3/utils/regedit.h >index 113f226..688bc72 100644 >--- a/source3/utils/regedit.h >+++ b/source3/utils/regedit.h >@@ -72,4 +72,8 @@ struct regedit_search_opts { > unsigned int search_nocase:1; > }; > >+#define PAIR_YELLOW_CYAN 1 >+#define PAIR_BLACK_CYAN 2 >+#define PAIR_YELLOW_BLUE 3 >+ > #endif >diff --git a/source3/utils/regedit_list.c b/source3/utils/regedit_list.c >new file mode 100644 >index 0000000..2da70bf >--- /dev/null >+++ b/source3/utils/regedit_list.c >@@ -0,0 +1,524 @@ >+/* >+ * Samba Unix/Linux SMB client library >+ * Registry Editor >+ * Copyright (C) Christopher Davis 2014 >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License as published by >+ * the Free Software Foundation; either version 3 of the License, or >+ * (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program. If not, see <http://www.gnu.org/licenses/>. >+ */ >+ >+#include "regedit_list.h" >+#include "regedit.h" >+ >+struct multilist { >+ WINDOW *window; >+ WINDOW *pad; >+ >+ unsigned window_height; >+ unsigned window_width; >+ unsigned start_row; >+ unsigned cursor_row; >+ >+ unsigned ncols; >+ struct multilist_column *columns; >+ >+ const void *data; >+ unsigned nrows; >+ const void *current_row; >+ const struct multilist_accessors *cb; >+}; >+ >+/* data getters */ >+static const void *data_get_first_row(struct multilist *list) >+{ >+ SMB_ASSERT(list->cb->get_first_row); >+ return list->cb->get_first_row(list->data); >+} >+ >+static const void *data_get_next_row(struct multilist *list, const void *row) >+{ >+ SMB_ASSERT(list->cb->get_next_row); >+ return list->cb->get_next_row(list->data, row); >+} >+ >+static const void *data_get_prev_row(struct multilist *list, const void *row) >+{ >+ const void *tmp, *next; >+ >+ if (list->cb->get_prev_row) { >+ return list->cb->get_prev_row(list->data, row); >+ } >+ >+ tmp = data_get_first_row(list); >+ if (tmp == row) { >+ return NULL; >+ } >+ >+ for (; tmp && (next = data_get_next_row(list, tmp)) != row; >+ tmp = next) { >+ } >+ >+ SMB_ASSERT(tmp != NULL); >+ >+ return tmp; >+} >+ >+static unsigned data_get_row_count(struct multilist *list) >+{ >+ unsigned i; >+ const void *row; >+ >+ if (list->cb->get_row_count) >+ return list->cb->get_row_count(list->data); >+ >+ for (i = 0, row = data_get_first_row(list); >+ row != NULL; >+ ++i, row = data_get_next_row(list, row)) { >+ } >+ >+ return i; >+} >+ >+static const void *data_get_row_n(struct multilist *list, size_t n) >+{ >+ unsigned i; >+ const void *row; >+ >+ if (list->cb->get_row_n) >+ return list->cb->get_row_n(list->data, n); >+ >+ for (i = 0, row = data_get_first_row(list); >+ i < n && row != NULL; >+ ++i, row = data_get_next_row(list, row)) { >+ } >+ >+ return row; >+} >+ >+static const char *data_get_column_header(struct multilist *list, unsigned col) >+{ >+ SMB_ASSERT(list->cb->get_column_header); >+ return list->cb->get_column_header(list->data, col); >+} >+ >+static const char *data_get_item_label(struct multilist *list, const void *row, >+ unsigned col) >+{ >+ SMB_ASSERT(list->cb->get_item_label); >+ return list->cb->get_item_label(row, col); >+} >+ >+static const char *data_get_item_prefix(struct multilist *list, const void *row, >+ unsigned col) >+{ >+ if (list->cb->get_item_prefix) >+ return list->cb->get_item_prefix(row, col); >+ return ""; >+} >+ >+static int multilist_free(struct multilist *list) >+{ >+ if (list->pad) { >+ delwin(list->pad); >+ } >+ >+ return 0; >+} >+ >+struct multilist *multilist_new(TALLOC_CTX *ctx, WINDOW *window, >+ const struct multilist_accessors *cb, >+ unsigned ncol) >+{ >+ struct multilist *list; >+ >+ SMB_ASSERT(ncol > 0); >+ >+ list = talloc_zero(ctx, struct multilist); >+ if (list == NULL) { >+ return NULL; >+ } >+ talloc_set_destructor(list, multilist_free); >+ >+ list->cb = cb; >+ list->ncols = ncol; >+ list->columns = talloc_zero_array(list, struct multilist_column, ncol); >+ if (list->columns == NULL) { >+ talloc_free(list); >+ return NULL; >+ } >+ multilist_set_window(list, window); >+ >+ return list; >+} >+ >+struct multilist_column *multilist_column_config(struct multilist *list, >+ unsigned col) >+{ >+ SMB_ASSERT(col < list->ncols); >+ return &list->columns[col]; >+} >+ >+static void put_padding(WINDOW *win, size_t col_width, size_t item_len) >+{ >+ size_t amt; >+ >+ SMB_ASSERT(item_len <= col_width); >+ >+ amt = col_width - item_len; >+ while (amt--) { >+ waddch(win, ' '); >+ } >+} >+ >+static void put_item(struct multilist *list, WINDOW *win, unsigned col, >+ const char *item, int attr) >+{ >+ bool append_sep = true; >+ unsigned i; >+ size_t len; >+ struct multilist_column *col_info; >+ bool trim = false; >+ >+ SMB_ASSERT(col < list->ncols); >+ SMB_ASSERT(item != NULL); >+ >+ if (col == list->ncols - 1) { >+ append_sep = false; >+ } >+ col_info = &list->columns[col]; >+ >+ len = strlen(item); >+ if (len > col_info->width) { >+ len = col_info->width; >+ trim = true; >+ } >+ >+ if (col_info->align_right) { >+ put_padding(win, col_info->width, len); >+ } >+ for (i = 0; i < len; ++i) { >+ if (i == len - 1 && trim) { >+ waddch(win, '~' | attr); >+ } else { >+ waddch(win, item[i] | attr); >+ } >+ } >+ if (!col_info->align_right) { >+ put_padding(win, col_info->width, len); >+ } >+ >+ if (append_sep) { >+ waddch(win, ' '); >+ waddch(win, '|'); >+ waddch(win, ' '); >+ } >+} >+ >+static void put_header(struct multilist *list) >+{ >+ unsigned col; >+ const char *header; >+ >+ if (!list->cb->get_column_header) { >+ return; >+ } >+ >+ wmove(list->window, 0, 0); >+ for (col = 0; col < list->ncols; ++col) { >+ header = data_get_column_header(list, col); >+ SMB_ASSERT(header != NULL); >+ put_item(list, list->window, col, header, >+ A_BOLD | COLOR_PAIR(PAIR_YELLOW_BLUE)); >+ } >+} >+ >+static WERROR put_data(struct multilist *list) >+{ >+ const void *row; >+ int ypos; >+ unsigned col; >+ const char *prefix, *item; >+ char *tmp; >+ >+ for (ypos = 0, row = data_get_first_row(list); >+ row != NULL; >+ row = data_get_next_row(list, row), ++ypos) { >+ wmove(list->pad, ypos, 0); >+ for (col = 0; col < list->ncols; ++col) { >+ prefix = data_get_item_prefix(list, row, col); >+ SMB_ASSERT(prefix != NULL); >+ item = data_get_item_label(list, row, col); >+ SMB_ASSERT(item != NULL); >+ tmp = talloc_asprintf(list, "%s%s", prefix, item); >+ if (tmp == NULL) { >+ return WERR_NOMEM; >+ } >+ put_item(list, list->pad, col, tmp, 0); >+ talloc_free(tmp); >+ } >+ } >+ >+ return WERR_OK; >+} >+ >+static struct multilist_column *find_widest_column(struct multilist *list) >+{ >+ unsigned col; >+ struct multilist_column *colp; >+ >+ SMB_ASSERT(list->ncols > 0); >+ colp = &list->columns[0]; >+ >+ for (col = 1; col < list->ncols; ++col) { >+ if (list->columns[col].width > colp->width) { >+ colp = &list->columns[col]; >+ } >+ } >+ >+ return colp; >+} >+ >+static WERROR calc_column_widths(struct multilist *list) >+{ >+ const void *row; >+ unsigned col; >+ size_t len; >+ const char *item; >+ size_t width, total_width, overflow; >+ >+ /* calculate the maximum widths for each column */ >+ for (col = 0; col < list->ncols; ++col) { >+ len = 0; >+ if (list->cb->get_column_header) { >+ item = data_get_column_header(list, col); >+ len = strlen(item); >+ } >+ list->columns[col].width = len; >+ } >+ >+ for (row = data_get_first_row(list); >+ row != NULL; >+ row = data_get_next_row(list, row)) { >+ for (col = 0; col < list->ncols; ++col) { >+ item = data_get_item_prefix(list, row, col); >+ SMB_ASSERT(item != NULL); >+ len = strlen(item); >+ >+ item = data_get_item_label(list, row, col); >+ SMB_ASSERT(item != NULL); >+ len += strlen(item); >+ if (len > list->columns[col].width) { >+ list->columns[col].width = len; >+ } >+ } >+ } >+ >+ /* calculate row width */ >+ for (width = 0, col = 0; col < list->ncols; ++col) { >+ width += list->columns[col].width; >+ } >+ /* width including column spacing and separations */ >+ total_width = width + (list->ncols - 1) * 3; >+ /* if everything fits, we're done */ >+ if (total_width <= list->window_width) { >+ return WERR_OK; >+ } >+ >+ overflow = total_width - list->window_width; >+ /* the window is so narrow that no amount of trimming will >+ help fit the data. just give up. */ >+ if (overflow > width) { >+ return WERR_OK; >+ } >+ >+ /* keep trimming from the widest column until the row fits */ >+ while (overflow) { >+ struct multilist_column *colp = find_widest_column(list); >+ size_t max_trim = colp->width / 3; >+ size_t trim = MIN(overflow, max_trim); >+ colp->width -= trim; >+ overflow -= trim; >+ } >+ >+ return WERR_OK; >+} >+ >+static void highlight_current_row(struct multilist *list) >+{ >+ mvwchgat(list->pad, list->cursor_row, 0, -1, A_REVERSE, 0, NULL); >+} >+ >+static void unhighlight_current_row(struct multilist *list) >+{ >+ mvwchgat(list->pad, list->cursor_row, 0, -1, A_NORMAL, 0, NULL); >+} >+ >+const void *multilist_get_data(struct multilist *list) >+{ >+ return list->data; >+} >+ >+WERROR multilist_set_data(struct multilist *list, const void *data) >+{ >+ WERROR rv; >+ >+ SMB_ASSERT(list->window != NULL); >+ list->data = data; >+ >+ calc_column_widths(list); >+ >+ if (list->pad) { >+ delwin(list->pad); >+ } >+ /* construct a pad that is exactly the width of the window, and >+ as tall as required to fit all data rows. */ >+ list->nrows = data_get_row_count(list); >+ list->pad = newpad(MAX(list->nrows, 1), list->window_width); >+ if (list->pad == NULL) { >+ return WERR_NOMEM; >+ } >+ >+ /* add the column headers to the window and render all rows to >+ the pad. */ >+ werase(list->window); >+ put_header(list); >+ rv = put_data(list); >+ if (!W_ERROR_IS_OK(rv)) { >+ return rv; >+ } >+ >+ /* initialize the cursor */ >+ list->start_row = 0; >+ list->cursor_row = 0; >+ list->current_row = data_get_first_row(list); >+ highlight_current_row(list); >+ >+ return WERR_OK; >+} >+ >+WERROR multilist_set_window(struct multilist *list, WINDOW *window) >+{ >+ int maxy, maxx; >+ bool rerender = false; >+ >+ getmaxyx(window, maxy, maxx); >+ >+ /* rerender pad if window width is different. */ >+ if (list->data && maxx != list->window_width) { >+ rerender = true; >+ } >+ >+ list->window = window; >+ list->window_width = maxx; >+ list->window_height = maxy; >+ if (rerender) { >+ return multilist_set_data(list, list->data); >+ } else { >+ put_header(list); >+ } >+ >+ return WERR_OK; >+} >+ >+void multilist_refresh(struct multilist *list) >+{ >+ int window_start_row, height; >+ >+ /* copy from pad, starting at start_row, to the window, accounting >+ for the column header (if present). */ >+ height = MIN(list->window_height, list->nrows); >+ window_start_row = 0; >+ if (list->cb->get_column_header) { >+ window_start_row = 1; >+ if (height < list->window_height) { >+ height++; >+ } >+ } >+ copywin(list->pad, list->window, list->start_row, 0, >+ window_start_row, 0, height - 1, list->window_width - 1, >+ false); >+} >+ >+static void fix_start_row(struct multilist *list) >+{ >+ int height; >+ >+ /* adjust start_row so that the cursor appears on the screen */ >+ >+ height = list->window_height; >+ if (list->cb->get_column_header) { >+ height--; >+ } >+ if (list->cursor_row < list->start_row) { >+ list->start_row = list->cursor_row; >+ } else if (list->cursor_row >= list->start_row + height) { >+ list->start_row = list->cursor_row - height + 1; >+ } >+} >+ >+void multilist_driver(struct multilist *list, int c) >+{ >+ const void *tmp; >+ >+ if (list->nrows == 0) { >+ return; >+ } >+ >+ switch (c) { >+ case ML_CURSOR_UP: >+ if (list->cursor_row == 0) { >+ return; >+ } >+ unhighlight_current_row(list); >+ list->cursor_row--; >+ tmp = data_get_prev_row(list, list->current_row); >+ break; >+ case ML_CURSOR_DOWN: >+ if (list->cursor_row == list->nrows - 1) { >+ return; >+ } >+ unhighlight_current_row(list); >+ list->cursor_row++; >+ tmp = data_get_next_row(list, list->current_row); >+ break; >+ } >+ >+ SMB_ASSERT(tmp); >+ list->current_row = tmp; >+ highlight_current_row(list); >+ fix_start_row(list); >+} >+ >+const void *multilist_get_current_row(struct multilist *list) >+{ >+ return list->current_row; >+} >+ >+void multilist_set_current_row(struct multilist *list, const void *row) >+{ >+ unsigned i; >+ const void *tmp; >+ >+ for (i = 0, tmp = data_get_first_row(list); >+ tmp != NULL; >+ ++i, tmp = data_get_next_row(list, tmp)) { >+ if (tmp == row) { >+ unhighlight_current_row(list); >+ list->cursor_row = i; >+ list->current_row = row; >+ highlight_current_row(list); >+ fix_start_row(list); >+ return; >+ } >+ } >+} >diff --git a/source3/utils/regedit_list.h b/source3/utils/regedit_list.h >new file mode 100644 >index 0000000..4b1840a >--- /dev/null >+++ b/source3/utils/regedit_list.h >@@ -0,0 +1,78 @@ >+/* >+ * Samba Unix/Linux SMB client library >+ * Registry Editor >+ * Copyright (C) Christopher Davis 2014 >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License as published by >+ * the Free Software Foundation; either version 3 of the License, or >+ * (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program. If not, see <http://www.gnu.org/licenses/>. >+ */ >+ >+#ifndef _REGEDIT_LIST_H_ >+#define _REGEDIT_LIST_H_ >+ >+#include "includes.h" >+#include <ncurses.h> >+ >+struct multilist_accessors { >+ /* (optional) return the column header for col */ >+ const char *(*get_column_header)(const void *data, unsigned col); >+ >+ /* return a pointer to the first row of data */ >+ const void *(*get_first_row)(const void *data); >+ >+ /* (optional) return a count of all data rows */ >+ size_t (*get_row_count)(const void *data); >+ >+ /* return the next row or NULL if there aren't any more */ >+ const void *(*get_next_row)(const void *data, const void *row); >+ >+ /* (optional) return the previous row or NULL if row is on top. */ >+ const void *(*get_prev_row)(const void *data, const void *row); >+ >+ /* (optional) return row n of data */ >+ const void *(*get_row_n)(const void *data, size_t n); >+ >+ /* return the label for row and col */ >+ const char *(*get_item_label)(const void *row, unsigned col); >+ >+ /* (optional) return a prefix string to be prepended to an item's >+ label. */ >+ const char *(*get_item_prefix)(const void *row, unsigned col); >+}; >+ >+struct multilist_column { >+ size_t width; >+ unsigned int align_right:1; >+}; >+ >+struct multilist; >+ >+struct multilist *multilist_new(TALLOC_CTX *ctx, WINDOW *window, >+ const struct multilist_accessors *cb, >+ unsigned ncol); >+struct multilist_column *multilist_column_config(struct multilist *list, >+ unsigned col); >+WERROR multilist_set_window(struct multilist *list, WINDOW *window); >+const void *multilist_get_data(struct multilist *list); >+WERROR multilist_set_data(struct multilist *list, const void *data); >+void multilist_refresh(struct multilist *list); >+ >+enum { >+ ML_CURSOR_UP, >+ ML_CURSOR_DOWN >+}; >+void multilist_driver(struct multilist *list, int c); >+const void *multilist_get_current_row(struct multilist *list); >+void multilist_set_current_row(struct multilist *list, const void *row); >+ >+#endif >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index ef85754..7e65c39 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -18,6 +18,7 @@ > */ > > #include "regedit_treeview.h" >+#include "regedit_list.h" > #include "lib/registry/registry.h" > > #define HEADING_X 3 >@@ -254,112 +255,47 @@ void tree_node_free_recursive(struct tree_node *list) > } > } > >-static void tree_view_free_current_items(ITEM **items) >-{ >- size_t i; >- struct tree_node *node; >- ITEM *item; >- >- if (items == NULL) { >- return; >- } >- >- for (i = 0; items[i] != NULL; ++i) { >- item = items[i]; >- node = item_userptr(item); >- if (node && node->label) { >- talloc_free(node->label); >- node->label = NULL; >- } >- free_item(item); >- } >- >- talloc_free(items); >-} >- > void tree_view_clear(struct tree_view *view) > { >- unpost_menu(view->menu); >- set_menu_items(view->menu, view->empty); >- tree_view_free_current_items(view->current_items); >- view->current_items = NULL; >+ multilist_set_data(view->list, NULL); > } > > WERROR tree_view_update(struct tree_view *view, struct tree_node *list) > { >- ITEM **items; >- struct tree_node *node; >- size_t i, n_items; >- >- if (list == NULL) { >- list = view->root; >- } >- for (n_items = 0, node = list; node != NULL; node = node->next) { >- n_items++; >- } >- >- items = talloc_zero_array(view, ITEM *, n_items + 1); >- if (items == NULL) { >- return WERR_NOMEM; >- } >- >- for (i = 0, node = list; node != NULL; ++i, node = node->next) { >- char prefix = ' '; >- >- /* Add a '+' marker to indicate that the item has >- descendants. */ >- if (tree_node_has_children(node)) { >- prefix = '+'; >- } >- >- SMB_ASSERT(node->label == NULL); >- node->label = talloc_asprintf(node, "%c%s", prefix, node->name); >- if (node->label == NULL) { >- goto fail; >- } >+ WERROR rv; > >- items[i] = new_item(node->label, node->name); >- set_item_userptr(items[i], node); >+ rv = multilist_set_data(view->list, list); >+ if (W_ERROR_IS_OK(rv)) { >+ multilist_refresh(view->list); > } > >- unpost_menu(view->menu); >- set_menu_items(view->menu, items); >- tree_view_free_current_items(view->current_items); >- view->current_items = items; >- >- return WERR_OK; >- >-fail: >- tree_view_free_current_items(items); >- >- return WERR_NOMEM; >+ return rv; > } > > /* is this node in the current level? */ > bool tree_view_is_node_visible(struct tree_view *view, struct tree_node *node) > { >- struct tree_node *first; >+ const struct tree_node *first; > >- first = item_userptr(view->current_items[0]); >+ first = multilist_get_data(view->list); > >- return first->parent == node->parent; >+ return first && first->parent == node->parent; > } > > void tree_view_set_current_node(struct tree_view *view, struct tree_node *node) > { >- ITEM **it; >- >- for (it = view->current_items; *it; ++it) { >- if (item_userptr(*it) == node) { >- set_current_item(view->menu, *it); >- return; >- } >- } >+ multilist_set_current_row(view->list, node); > } > > struct tree_node *tree_view_get_current_node(struct tree_view *view) > { >- return item_userptr(current_item(view->menu)); >+ return discard_const_p(struct tree_node, >+ multilist_get_current_row(view->list)); >+} >+ >+void tree_view_driver(struct tree_view *view, int c) >+{ >+ multilist_driver(view->list, c); > } > > void tree_view_set_selected(struct tree_view *view, bool select) >@@ -374,18 +310,14 @@ void tree_view_set_selected(struct tree_view *view, bool select) > > void tree_view_show(struct tree_view *view) > { >- post_menu(view->menu); >+ multilist_refresh(view->list); >+ touchwin(view->window); >+ wnoutrefresh(view->window); >+ wnoutrefresh(view->sub); > } > > static int tree_view_free(struct tree_view *view) > { >- if (view->menu) { >- unpost_menu(view->menu); >- free_menu(view->menu); >- } >- if (view->empty[0]) { >- free_item(view->empty[0]); >- } > if (view->panel) { > del_panel(view->panel); > } >@@ -395,18 +327,69 @@ static int tree_view_free(struct tree_view *view) > if (view->window) { > delwin(view->window); > } >- tree_view_free_current_items(view->current_items); > tree_node_free_recursive(view->root); > > return 0; > } > >+static const char *tv_get_column_header(const void *data, unsigned col) >+{ >+ SMB_ASSERT(col == 0); >+ return "Name"; >+} >+ >+static const void *tv_get_first_row(const void *data) >+{ >+ return data; >+} >+ >+static const void *tv_get_next_row(const void *data, const void *row) >+{ >+ const struct tree_node *node = row; >+ SMB_ASSERT(node != NULL); >+ return node->next; >+} >+ >+static const void *tv_get_prev_row(const void *data, const void *row) >+{ >+ const struct tree_node *node = row; >+ SMB_ASSERT(node != NULL); >+ return node->previous; >+} >+ >+static const char *tv_get_item_prefix(const void *row, unsigned col) >+{ >+ struct tree_node *node = discard_const_p(struct tree_node, row); >+ SMB_ASSERT(col == 0); >+ SMB_ASSERT(node != NULL); >+ if (tree_node_has_children(node)) { >+ return "+"; >+ } >+ return " "; >+} >+ >+static const char *tv_get_item_label(const void *row, unsigned col) >+{ >+ const struct tree_node *node = row; >+ SMB_ASSERT(col == 0); >+ SMB_ASSERT(node != NULL); >+ return node->name; >+} >+ >+static struct multilist_accessors tv_accessors = { >+ .get_column_header = tv_get_column_header, >+ .get_first_row = tv_get_first_row, >+ .get_next_row = tv_get_next_row, >+ .get_prev_row = tv_get_prev_row, >+ .get_item_prefix = tv_get_item_prefix, >+ .get_item_label = tv_get_item_label >+}; >+ > struct tree_view *tree_view_new(TALLOC_CTX *ctx, struct tree_node *root, > int nlines, int ncols, int begin_y, > int begin_x) > { > struct tree_view *view; >- static const char *dummy = "(empty)"; > > view = talloc_zero(ctx, struct tree_view); > if (view == NULL) { >@@ -415,10 +398,6 @@ struct tree_view *tree_view_new(TALLOC_CTX *ctx, struct tree_node *root, > > talloc_set_destructor(view, tree_view_free); > >- view->empty[0] = new_item(dummy, dummy); >- if (view->empty[0] == NULL) { >- goto fail; >- } > view->window = newwin(nlines, ncols, begin_y, begin_x); > if (view->window == NULL) { > goto fail; >@@ -437,16 +416,10 @@ struct tree_view *tree_view_new(TALLOC_CTX *ctx, struct tree_node *root, > } > view->root = root; > >- view->menu = new_menu(view->empty); >- if (view->menu == NULL) { >+ view->list = multilist_new(view, view->sub, &tv_accessors, 1); >+ if (view->list == NULL) { > goto fail; > } >- set_menu_format(view->menu, nlines, 1); >- set_menu_win(view->menu, view->window); >- set_menu_sub(view->menu, view->sub); >- menu_opts_off(view->menu, O_SHOWDESC); >- set_menu_mark(view->menu, "* "); >- > tree_view_update(view, root); > > return view; >@@ -458,11 +431,10 @@ fail: > } > > void tree_view_resize(struct tree_view *view, int nlines, int ncols, >- int begin_y, int begin_x) >+ int begin_y, int begin_x) > { > WINDOW *nwin, *nsub; > >- unpost_menu(view->menu); > nwin = newwin(nlines, ncols, begin_y, begin_x); > nsub = subwin(nwin, nlines - 2, ncols - 2, begin_y + 1, begin_x + 1); > replace_panel(view->panel, nwin); >@@ -472,10 +444,7 @@ void tree_view_resize(struct tree_view *view, int nlines, int ncols, > view->sub = nsub; > box(view->window, 0, 0); > mvwprintw(view->window, 0, HEADING_X, "Key"); >- set_menu_format(view->menu, nlines, 1); >- set_menu_win(view->menu, view->window); >- set_menu_sub(view->menu, view->sub); >- post_menu(view->menu); >+ multilist_set_window(view->list, view->sub); > } > > static void print_path_recursive(WINDOW *label, struct tree_node *node, >diff --git a/source3/utils/regedit_treeview.h b/source3/utils/regedit_treeview.h >index 152ba3c..cd17a3c 100644 >--- a/source3/utils/regedit_treeview.h >+++ b/source3/utils/regedit_treeview.h >@@ -22,7 +22,6 @@ > > #include "includes.h" > #include <ncurses.h> >-#include <menu.h> > #include <panel.h> > > struct registry_key; >@@ -30,7 +29,6 @@ struct registry_key; > struct tree_node { > > char *name; >- char *label; > struct registry_key *key; > > struct tree_node *parent; >@@ -39,15 +37,15 @@ struct tree_node { > struct tree_node *next; > }; > >+struct multilist; >+ > struct tree_view { > > struct tree_node *root; > WINDOW *window; > WINDOW *sub; > PANEL *panel; >- MENU *menu; >- ITEM **current_items; >- ITEM *empty[2]; >+ struct multilist *list; > }; > > struct tree_node *tree_node_new(TALLOC_CTX *ctx, struct tree_node *parent, >@@ -74,5 +72,6 @@ void tree_node_insert_sorted(struct tree_node *list, struct tree_node *node); > bool tree_view_is_node_visible(struct tree_view *view, struct tree_node *node); > void tree_view_set_current_node(struct tree_view *view, struct tree_node *node); > struct tree_node *tree_view_get_current_node(struct tree_view *view); >+void tree_view_driver(struct tree_view *view, int c); > > #endif >diff --git a/source3/wscript_build b/source3/wscript_build >index 9103b14..7394a57 100755 >--- a/source3/wscript_build >+++ b/source3/wscript_build >@@ -1459,7 +1459,7 @@ bld.SAMBA3_BINARY('samba-regedit', > source="""utils/regedit.c utils/regedit_samba3.c > utils/regedit_wrap.c utils/regedit_treeview.c > utils/regedit_valuelist.c utils/regedit_dialog.c >- utils/regedit_hexedit.c""", >+ utils/regedit_hexedit.c utils/regedit_list.c""", > deps='ncurses menu panel form registry param popt_samba3 smbregistry', > enabled=bld.env.build_regedit) > >-- >2.1.1 > > >From b3ad33e1d6aa0fb432bf531fa7a11a3f6b898845 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Tue, 10 Jun 2014 10:35:19 -0700 >Subject: [PATCH 10/45] regedit: make value list display data in multiple > columns > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit ec6a7a7335f5b9e3a54b9967563ba198fc67b120) >--- > source3/utils/regedit.c | 8 +- > source3/utils/regedit_treeview.c | 1 + > source3/utils/regedit_valuelist.c | 274 ++++++++++++++++++++++---------------- > source3/utils/regedit_valuelist.h | 16 ++- > 4 files changed, 171 insertions(+), 128 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index ea9aec8..b8f442c 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -435,10 +435,10 @@ static void handle_value_input(struct regedit *regedit, int c) > > switch (c) { > case KEY_DOWN: >- menu_driver(regedit->vl->menu, REQ_DOWN_ITEM); >+ value_list_driver(regedit->vl, ML_CURSOR_DOWN); > break; > case KEY_UP: >- menu_driver(regedit->vl->menu, REQ_UP_ITEM); >+ value_list_driver(regedit->vl, ML_CURSOR_UP); > break; > case 'b': > case 'B': >@@ -446,7 +446,7 @@ static void handle_value_input(struct regedit *regedit, int c) > /* Falthrough... */ > case '\n': > case KEY_ENTER: >- vitem = item_userptr(current_item(regedit->vl->menu)); >+ vitem = value_list_get_current_item(regedit->vl); > if (vitem) { > struct tree_node *node; > node = tree_view_get_current_node(regedit->keys); >@@ -472,7 +472,7 @@ static void handle_value_input(struct regedit *regedit, int c) > } > case 'd': > case 'D': >- vitem = item_userptr(current_item(regedit->vl->menu)); >+ vitem = value_list_get_current_item(regedit->vl); > if (vitem) { > int sel; > >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index 7e65c39..ee6b631 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -445,6 +445,7 @@ void tree_view_resize(struct tree_view *view, int nlines, int ncols, > box(view->window, 0, 0); > mvwprintw(view->window, 0, HEADING_X, "Key"); > multilist_set_window(view->list, view->sub); >+ tree_view_show(view); > } > > static void print_path_recursive(WINDOW *label, struct tree_node *node, >diff --git a/source3/utils/regedit_valuelist.c b/source3/utils/regedit_valuelist.c >index 791a8ca..4922cdb 100644 >--- a/source3/utils/regedit_valuelist.c >+++ b/source3/utils/regedit_valuelist.c >@@ -18,39 +18,13 @@ > */ > > #include "regedit_valuelist.h" >+#include "regedit_list.h" > #include "lib/registry/registry.h" > > #define HEADING_X 3 > >-static void value_list_free_items(ITEM **items) >-{ >- size_t i; >- ITEM *item; >- struct value_item *vitem; >- >- if (items == NULL) { >- return; >- } >- >- for (i = 0; items[i] != NULL; ++i) { >- item = items[i]; >- vitem = item_userptr(item); >- SMB_ASSERT(vitem != NULL); >- free_item(item); >- } >- >- talloc_free(items); >-} >- > static int value_list_free(struct value_list *vl) > { >- if (vl->menu) { >- unpost_menu(vl->menu); >- free_menu(vl->menu); >- } >- if (vl->empty && vl->empty[0]) { >- free_item(vl->empty[0]); >- } > if (vl->panel) { > del_panel(vl->panel); > } >@@ -60,16 +34,94 @@ static int value_list_free(struct value_list *vl) > if (vl->window) { > delwin(vl->window); > } >- value_list_free_items(vl->items); > > return 0; > } > >+static const char *vl_get_column_header(const void *data, unsigned col) >+{ >+ switch (col) { >+ case 0: >+ return "Name"; >+ case 1: >+ return "Type"; >+ case 2: >+ return "Data"; >+ } >+ >+ return "???"; >+} >+ >+static const void *vl_get_first_row(const void *data) >+{ >+ const struct value_list *vl = data; >+ >+ if (vl && vl->nvalues) { >+ return &vl->values[0]; >+ } >+ return NULL; >+} >+ >+static const void *vl_get_next_row(const void *data, const void *row) >+{ >+ const struct value_list *vl = data; >+ const struct value_item *value = row; >+ >+ SMB_ASSERT(vl != NULL); >+ SMB_ASSERT(value != NULL); >+ if (value == &vl->values[vl->nvalues - 1]) { >+ return NULL; >+ } >+ >+ return value + 1; >+} >+ >+static const void *vl_get_prev_row(const void *data, const void *row) >+{ >+ const struct value_list *vl = data; >+ const struct value_item *value = row; >+ >+ SMB_ASSERT(vl != NULL); >+ SMB_ASSERT(value != NULL); >+ if (value == &vl->values[0]) { >+ return NULL; >+ } >+ >+ return value - 1; >+} >+ >+static const char *vl_get_item_label(const void *row, unsigned col) >+{ >+ const struct value_item *value = row; >+ >+ SMB_ASSERT(value != NULL); >+ SMB_ASSERT(value->value_name != NULL); >+ switch (col) { >+ case 0: >+ return value->value_name; >+ case 1: >+ return str_regtype(value->type); >+ case 2: >+ if (value->value) { >+ return value->value; >+ } >+ return ""; >+ } >+ >+ return "???"; >+} >+ >+static struct multilist_accessors vl_accessors = { >+ .get_column_header = vl_get_column_header, >+ .get_first_row = vl_get_first_row, >+ .get_next_row = vl_get_next_row, >+ .get_prev_row = vl_get_prev_row, >+ .get_item_label = vl_get_item_label >+}; >+ > struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols, > int begin_y, int begin_x) > { >- static const char *empty = "(no values)"; >- static const char *empty_desc = ""; > struct value_list *vl; > > vl = talloc_zero(ctx, struct value_list); >@@ -79,15 +131,6 @@ struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols, > > talloc_set_destructor(vl, value_list_free); > >- vl->empty = talloc_zero_array(vl, ITEM *, 2); >- if (vl->empty == NULL) { >- goto fail; >- } >- vl->empty[0] = new_item(empty, empty_desc); >- if (vl->empty[0] == NULL) { >- goto fail; >- } >- > vl->window = newwin(nlines, ncols, begin_y, begin_x); > if (vl->window == NULL) { > goto fail; >@@ -105,18 +148,11 @@ struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols, > goto fail; > } > >- vl->menu = new_menu(vl->empty); >- if (vl->menu == NULL) { >+ vl->list = multilist_new(vl, vl->sub, &vl_accessors, 3); >+ if (vl->list == NULL) { > goto fail; > } > >- set_menu_format(vl->menu, nlines, 1); >- set_menu_win(vl->menu, vl->window); >- set_menu_sub(vl->menu, vl->sub); >- >- menu_opts_on(vl->menu, O_SHOWDESC); >- set_menu_mark(vl->menu, "* "); >- > return vl; > > fail: >@@ -140,7 +176,6 @@ void value_list_resize(struct value_list *vl, int nlines, int ncols, > { > WINDOW *nwin, *nsub; > >- unpost_menu(vl->menu); > nwin = newwin(nlines, ncols, begin_y, begin_x); > nsub = subwin(nwin, nlines - 2, ncols - 2, begin_y + 1, begin_x + 1); > replace_panel(vl->panel, nwin); >@@ -150,10 +185,8 @@ void value_list_resize(struct value_list *vl, int nlines, int ncols, > vl->sub = nsub; > box(vl->window, 0, 0); > mvwprintw(vl->window, 0, HEADING_X, "Value"); >- set_menu_format(vl->menu, nlines, 1); >- set_menu_win(vl->menu, vl->window); >- set_menu_sub(vl->menu, vl->sub); >- post_menu(vl->menu); >+ multilist_set_window(vl->list, vl->sub); >+ value_list_show(vl); > } > > static uint32_t get_num_values(TALLOC_CTX *ctx, const struct registry_key *key) >@@ -181,7 +214,10 @@ static uint32_t get_num_values(TALLOC_CTX *ctx, const struct registry_key *key) > > void value_list_show(struct value_list *vl) > { >- post_menu(vl->menu); >+ multilist_refresh(vl->list); >+ touchwin(vl->window); >+ wnoutrefresh(vl->window); >+ wnoutrefresh(vl->sub); > } > > static bool string_is_printable(const char *s) >@@ -197,7 +233,7 @@ static bool string_is_printable(const char *s) > return true; > } > >-static WERROR append_data_summary(struct value_item *vitem) >+static WERROR append_data_summary(TALLOC_CTX *ctx, struct value_item *vitem) > { > char *tmp = NULL; > >@@ -209,42 +245,53 @@ static WERROR append_data_summary(struct value_item *vitem) > if (vitem->data.length >= 4) { > v = IVAL(vitem->data.data, 0); > } >- tmp = talloc_asprintf_append(vitem->value_desc, "(0x%x)", v); >+ tmp = talloc_asprintf(ctx, "0x%08x (%u)", v, v); > break; > } > case REG_SZ: > case REG_EXPAND_SZ: { > const char *s; > >- if (!pull_reg_sz(vitem, &vitem->data, &s)) { >+ if (!pull_reg_sz(ctx, &vitem->data, &s)) { > break; > } > vitem->unprintable = !string_is_printable(s); > if (vitem->unprintable) { >- tmp = talloc_asprintf_append(vitem->value_desc, >- "(unprintable)"); >+ tmp = talloc_asprintf(ctx, "(unprintable)"); > } else { >- tmp = talloc_asprintf_append(vitem->value_desc, >- "(\"%s\")", s); >+ tmp = talloc_asprintf(ctx, "%s", s); > } > break; > } > case REG_MULTI_SZ: { >- size_t i; >+ size_t i, len; > const char **a; >+ const char *val; > >- if (!pull_reg_multi_sz(vitem, &vitem->data, &a)) { >+ if (!pull_reg_multi_sz(ctx, &vitem->data, &a)) { > break; > } >- tmp = vitem->value_desc; >- for (i = 0; a[i] != NULL; ++i) { >+ for (len = 0; a[len] != NULL; ++len) { >+ } >+ tmp = talloc_asprintf(ctx, "(%u) ", (unsigned)len); >+ if (tmp == NULL) { >+ return WERR_NOMEM; >+ } >+ for (i = 0; i < len; ++i) { > if (!string_is_printable(a[i])) { >- tmp = talloc_asprintf_append(tmp, >- "(unprintable)"); >+ val = "(unprintable)"; > vitem->unprintable = true; > } else { >- tmp = talloc_asprintf_append(tmp, "\"%s\" ", >- a[i]); >+ val = a[i]; >+ } >+ if (i == len - 1) { >+ tmp = talloc_asprintf_append(tmp, >+ "[%u]=\"%s\"", >+ (unsigned)i, val); >+ } else { >+ tmp = talloc_asprintf_append(tmp, >+ "[%u]=\"%s\", ", >+ (unsigned)i, val); > } > if (tmp == NULL) { > return WERR_NOMEM; >@@ -253,12 +300,11 @@ static WERROR append_data_summary(struct value_item *vitem) > break; > } > case REG_BINARY: >- tmp = talloc_asprintf_append(vitem->value_desc, "(%d bytes)", >- (int)vitem->data.length); >+ tmp = talloc_asprintf(ctx, "(%d bytes)", >+ (int)vitem->data.length); > break; > default: >- tmp = talloc_asprintf_append(vitem->value_desc, >- "(<unprintable>)"); >+ tmp = talloc_asprintf(ctx, "(unknown)"); > break; > } > >@@ -266,80 +312,74 @@ static WERROR append_data_summary(struct value_item *vitem) > return WERR_NOMEM; > } > >- vitem->value_desc = tmp; >+ vitem->value = tmp; > > return WERR_OK; > } > >+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) > { >- uint32_t n_values; >+ uint32_t nvalues; > uint32_t idx; >- struct value_item *vitem; >- ITEM **new_items; >+ struct value_item *vitem, *new_items; > WERROR rv; >- static const char *empty_name = "(empty)"; >- const char *name; > >- unpost_menu(vl->menu); >+ multilist_set_data(vl->list, NULL); >+ vl->nvalues = 0; >+ TALLOC_FREE(vl->values); > >- n_values = get_num_values(vl, key); >- if (n_values == 0) { >- set_menu_items(vl->menu, vl->empty); >+ nvalues = get_num_values(vl, key); >+ if (nvalues == 0) { > return WERR_OK; > } > >- new_items = talloc_zero_array(vl, ITEM *, n_values + 1); >+ new_items = talloc_zero_array(vl, struct value_item, nvalues); > if (new_items == NULL) { > return WERR_NOMEM; > } > >- for (idx = 0; idx < n_values; ++idx) { >- vitem = talloc_zero(new_items, struct value_item); >- if (vitem == NULL) { >- return WERR_NOMEM; >- } >- >- rv = reg_key_get_value_by_index(vitem, key, idx, >+ for (idx = 0; idx < nvalues; ++idx) { >+ vitem = &new_items[idx]; >+ rv = reg_key_get_value_by_index(new_items, key, idx, > &vitem->value_name, > &vitem->type, > &vitem->data); >- > if (!W_ERROR_IS_OK(rv)) { >- talloc_free(vitem); >+ talloc_free(new_items); > return rv; > } > >- vitem->value_desc = talloc_asprintf(vitem, "%-14s", >- str_regtype(vitem->type)); >- if (vitem->value_desc == NULL) { >- talloc_free(vitem); >- return rv; >- } >- >- rv = append_data_summary(vitem); >+ rv = append_data_summary(new_items, vitem); > if (!W_ERROR_IS_OK(rv)) { >- talloc_free(vitem); >+ talloc_free(new_items); > return rv; > } >+ } > >- /* ncurses won't accept empty strings in menu items */ >- name = vitem->value_name; >- if (name[0] == '\0') { >- name = empty_name; >- } >- new_items[idx] = new_item(name, vitem->value_desc); >- if (new_items[idx] == NULL) { >- talloc_free(vitem); >- return WERR_NOMEM; >- } >+ TYPESAFE_QSORT(new_items, nvalues, vitem_cmp); > >- set_item_userptr(new_items[idx], vitem); >+ vl->nvalues = nvalues; >+ vl->values = new_items; >+ rv = multilist_set_data(vl->list, vl); >+ if (W_ERROR_IS_OK(rv)) { >+ multilist_refresh(vl->list); > } > >- set_menu_items(vl->menu, new_items); >- value_list_free_items(vl->items); >- vl->items = new_items; >+ return rv; >+} > >- return WERR_OK; >+struct value_item *value_list_get_current_item(struct value_list *vl) >+{ >+ return discard_const_p(struct value_item, >+ multilist_get_current_row(vl->list)); >+} >+ >+void value_list_driver(struct value_list *vl, int c) >+{ >+ multilist_driver(vl->list, c); > } >diff --git a/source3/utils/regedit_valuelist.h b/source3/utils/regedit_valuelist.h >index 16b0d50..ea67075 100644 >--- a/source3/utils/regedit_valuelist.h >+++ b/source3/utils/regedit_valuelist.h >@@ -22,7 +22,6 @@ > > #include "includes.h" > #include <ncurses.h> >-#include <menu.h> > #include <panel.h> > > struct registry_key; >@@ -31,19 +30,20 @@ struct value_item { > uint32_t type; > DATA_BLOB data; > const char *value_name; >- char *value_desc; >+ char *value; > bool unprintable; > }; > >+struct multilist; >+ > struct value_list { > WINDOW *window; > WINDOW *sub; > PANEL *panel; >- MENU *menu; >- ITEM **items; >- ITEM **empty; >-} >-; >+ size_t nvalues; >+ struct value_item *values; >+ struct multilist *list; >+}; > 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); >@@ -51,5 +51,7 @@ void value_list_set_selected(struct value_list *vl, bool select); > 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); >+struct value_item *value_list_get_current_item(struct value_list *vl); >+void value_list_driver(struct value_list *vl, int c); > > #endif >-- >2.1.1 > > >From e5849a3e56abb60eda2ed39e3ced3b1e357b27d4 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Wed, 11 Jun 2014 10:40:38 -0700 >Subject: [PATCH 11/45] regedit: restore list cursor when window is resized > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit d38eba5244d0615994249070adee1f3df4c0d4aa) >--- > source3/utils/regedit_list.c | 43 +++++++++++++++++++++++++------------------ > 1 file changed, 25 insertions(+), 18 deletions(-) > >diff --git a/source3/utils/regedit_list.c b/source3/utils/regedit_list.c >index 2da70bf..417dea8 100644 >--- a/source3/utils/regedit_list.c >+++ b/source3/utils/regedit_list.c >@@ -406,6 +406,23 @@ WERROR multilist_set_data(struct multilist *list, const void *data) > return WERR_OK; > } > >+static void fix_start_row(struct multilist *list) >+{ >+ int height; >+ >+ /* adjust start_row so that the cursor appears on the screen */ >+ >+ height = list->window_height; >+ if (list->cb->get_column_header) { >+ height--; >+ } >+ if (list->cursor_row < list->start_row) { >+ list->start_row = list->cursor_row; >+ } else if (list->cursor_row >= list->start_row + height) { >+ list->start_row = list->cursor_row - height + 1; >+ } >+} >+ > WERROR multilist_set_window(struct multilist *list, WINDOW *window) > { > int maxy, maxx; >@@ -421,10 +438,17 @@ WERROR multilist_set_window(struct multilist *list, WINDOW *window) > list->window = window; > list->window_width = maxx; > list->window_height = maxy; >+ list->start_row = 0; > if (rerender) { >- return multilist_set_data(list, list->data); >+ const void *row = multilist_get_current_row(list); >+ WERROR rv = multilist_set_data(list, list->data); >+ if (W_ERROR_IS_OK(rv) && row) { >+ multilist_set_current_row(list, row); >+ } >+ return rv; > } else { > put_header(list); >+ fix_start_row(list); > } > > return WERR_OK; >@@ -449,23 +473,6 @@ void multilist_refresh(struct multilist *list) > false); > } > >-static void fix_start_row(struct multilist *list) >-{ >- int height; >- >- /* adjust start_row so that the cursor appears on the screen */ >- >- height = list->window_height; >- if (list->cb->get_column_header) { >- height--; >- } >- if (list->cursor_row < list->start_row) { >- list->start_row = list->cursor_row; >- } else if (list->cursor_row >= list->start_row + height) { >- list->start_row = list->cursor_row - height + 1; >- } >-} >- > void multilist_driver(struct multilist *list, int c) > { > const void *tmp; >-- >2.1.1 > > >From 7339bb6b33447cfc5fc337bd313c7238e7e73786 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Sat, 14 Jun 2014 14:13:10 -0700 >Subject: [PATCH 12/45] regedit: use talloc typesafety features > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit c85cc6b8360284c64d60ff4d09ca8d5e03188f7b) >--- > source3/utils/regedit_treeview.c | 31 ++++++++++++++++++++----------- > source3/utils/regedit_valuelist.c | 20 +++++++++++++------- > 2 files changed, 33 insertions(+), 18 deletions(-) > >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index ee6b631..47765c1 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -289,8 +289,8 @@ void tree_view_set_current_node(struct tree_view *view, struct tree_node *node) > > struct tree_node *tree_view_get_current_node(struct tree_view *view) > { >- return discard_const_p(struct tree_node, >- multilist_get_current_row(view->list)); >+ const void *row = multilist_get_current_row(view->list); >+ return talloc_get_type_abort(row, struct tree_node); > } > > void tree_view_driver(struct tree_view *view, int c) >@@ -340,28 +340,36 @@ static const char *tv_get_column_header(const void *data, unsigned col) > > static const void *tv_get_first_row(const void *data) > { >- return data; >+ if (data == NULL) { >+ return NULL; >+ } >+ >+ return talloc_get_type_abort(data, struct tree_node); > } > > static const void *tv_get_next_row(const void *data, const void *row) > { >- const struct tree_node *node = row; >- SMB_ASSERT(node != NULL); >+ const struct tree_node *node; >+ SMB_ASSERT(row != NULL); >+ node = talloc_get_type_abort(row, struct tree_node); > return node->next; > } > > static const void *tv_get_prev_row(const void *data, const void *row) > { >- const struct tree_node *node = row; >- SMB_ASSERT(node != NULL); >+ const struct tree_node *node; >+ SMB_ASSERT(row != NULL); >+ node = talloc_get_type_abort(row, struct tree_node); > return node->previous; > } > > static const char *tv_get_item_prefix(const void *row, unsigned col) > { >- struct tree_node *node = discard_const_p(struct tree_node, row); >+ struct tree_node *node; >+ > SMB_ASSERT(col == 0); >- SMB_ASSERT(node != NULL); >+ SMB_ASSERT(row != NULL); >+ node = talloc_get_type_abort(row, struct tree_node); > if (tree_node_has_children(node)) { > return "+"; > } >@@ -370,9 +378,10 @@ static const char *tv_get_item_prefix(const void *row, unsigned col) > > static const char *tv_get_item_label(const void *row, unsigned col) > { >- const struct tree_node *node = row; >+ const struct tree_node *node; > SMB_ASSERT(col == 0); >- SMB_ASSERT(node != NULL); >+ SMB_ASSERT(row != NULL); >+ node = talloc_get_type_abort(row, struct tree_node); > return node->name; > } > >diff --git a/source3/utils/regedit_valuelist.c b/source3/utils/regedit_valuelist.c >index 4922cdb..1c80c09 100644 >--- a/source3/utils/regedit_valuelist.c >+++ b/source3/utils/regedit_valuelist.c >@@ -54,21 +54,26 @@ static const char *vl_get_column_header(const void *data, unsigned col) > > static const void *vl_get_first_row(const void *data) > { >- const struct value_list *vl = data; >+ const struct value_list *vl; > >- if (vl && vl->nvalues) { >- return &vl->values[0]; >+ if (data) { >+ vl = talloc_get_type_abort(data, struct value_list); >+ if (vl->nvalues) { >+ return &vl->values[0]; >+ } > } >+ > return NULL; > } > > static const void *vl_get_next_row(const void *data, const void *row) > { >- const struct value_list *vl = data; >+ const struct value_list *vl; > const struct value_item *value = row; > >- SMB_ASSERT(vl != NULL); >+ SMB_ASSERT(data != NULL); > SMB_ASSERT(value != NULL); >+ vl = talloc_get_type_abort(data, struct value_list); > if (value == &vl->values[vl->nvalues - 1]) { > return NULL; > } >@@ -78,11 +83,12 @@ static const void *vl_get_next_row(const void *data, const void *row) > > static const void *vl_get_prev_row(const void *data, const void *row) > { >- const struct value_list *vl = data; >+ const struct value_list *vl; > const struct value_item *value = row; > >- SMB_ASSERT(vl != NULL); >+ SMB_ASSERT(data != NULL); > SMB_ASSERT(value != NULL); >+ vl = talloc_get_type_abort(data, struct value_list); > if (value == &vl->values[0]) { > return NULL; > } >-- >2.1.1 > > >From 4a098be77c9178293d58bf0af87c3072a50d9966 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Mon, 16 Jun 2014 17:36:16 -0700 >Subject: [PATCH 13/45] regedit: handle awkward window sizes better > >This fixes some assertion failures and an infinte loop that occurs >when the terminal window is shrunk down far enough to the point >regedit can't fit everything on screen. > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 55662513e14c026eb4cfa044ed772b31be5d6ab9) >--- > source3/utils/regedit_list.c | 23 +++++++++++------------ > source3/utils/regedit_treeview.c | 7 +++++++ > source3/utils/regedit_valuelist.c | 7 +++++++ > 3 files changed, 25 insertions(+), 12 deletions(-) > >diff --git a/source3/utils/regedit_list.c b/source3/utils/regedit_list.c >index 417dea8..ac4e240 100644 >--- a/source3/utils/regedit_list.c >+++ b/source3/utils/regedit_list.c >@@ -271,6 +271,7 @@ static WERROR put_data(struct multilist *list) > return WERR_OK; > } > >+#define MIN_WIDTH 3 > static struct multilist_column *find_widest_column(struct multilist *list) > { > unsigned col; >@@ -285,6 +286,10 @@ static struct multilist_column *find_widest_column(struct multilist *list) > } > } > >+ if (colp->width < MIN_WIDTH) { >+ return NULL; >+ } >+ > return colp; > } > >@@ -295,6 +300,7 @@ static WERROR calc_column_widths(struct multilist *list) > size_t len; > const char *item; > size_t width, total_width, overflow; >+ struct multilist_column *colp; > > /* calculate the maximum widths for each column */ > for (col = 0; col < list->ncols; ++col) { >@@ -335,19 +341,12 @@ static WERROR calc_column_widths(struct multilist *list) > } > > overflow = total_width - list->window_width; >- /* the window is so narrow that no amount of trimming will >- help fit the data. just give up. */ >- if (overflow > width) { >- return WERR_OK; >- } > >- /* keep trimming from the widest column until the row fits */ >- while (overflow) { >- struct multilist_column *colp = find_widest_column(list); >- size_t max_trim = colp->width / 3; >- size_t trim = MIN(overflow, max_trim); >- colp->width -= trim; >- overflow -= trim; >+ /* attempt to trim as much as possible to fit all the columns to >+ the window */ >+ while (overflow && (colp = find_widest_column(list))) { >+ colp->width--; >+ overflow--; > } > > return WERR_OK; >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index 47765c1..9962ad9 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -445,7 +445,14 @@ void tree_view_resize(struct tree_view *view, int nlines, int ncols, > WINDOW *nwin, *nsub; > > nwin = newwin(nlines, ncols, begin_y, begin_x); >+ if (nwin == NULL) { >+ return; >+ } > nsub = subwin(nwin, nlines - 2, ncols - 2, begin_y + 1, begin_x + 1); >+ if (nsub == NULL) { >+ delwin(nwin); >+ return; >+ } > replace_panel(view->panel, nwin); > delwin(view->sub); > delwin(view->window); >diff --git a/source3/utils/regedit_valuelist.c b/source3/utils/regedit_valuelist.c >index 1c80c09..9557c8c 100644 >--- a/source3/utils/regedit_valuelist.c >+++ b/source3/utils/regedit_valuelist.c >@@ -183,7 +183,14 @@ void value_list_resize(struct value_list *vl, int nlines, int ncols, > WINDOW *nwin, *nsub; > > nwin = newwin(nlines, ncols, begin_y, begin_x); >+ if (nwin == NULL) { >+ return; >+ } > nsub = subwin(nwin, nlines - 2, ncols - 2, begin_y + 1, begin_x + 1); >+ if (nsub == NULL) { >+ delwin(nwin); >+ return; >+ } > replace_panel(vl->panel, nwin); > delwin(vl->sub); > delwin(vl->window); >-- >2.1.1 > > >From 720ae399ef2580a41116ecb40c1ac5a1867cdd7a Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Wed, 25 Jun 2014 21:48:52 -0700 >Subject: [PATCH 14/45] regedit: notify user if there's a failure loading > subkeys > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 0b334dd1911206bac633421e1667052200574d29) >--- > source3/utils/regedit.c | 15 +++++++++++---- > 1 file changed, 11 insertions(+), 4 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index b8f442c..7a47db2 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -361,10 +361,17 @@ static void handle_tree_input(struct regedit *regedit, int c) > case KEY_RIGHT: > node = tree_view_get_current_node(regedit->keys); > if (node && tree_node_has_children(node)) { >- tree_node_load_children(node); >- print_path(regedit, node->child_head); >- tree_view_update(regedit->keys, node->child_head); >- value_list_load(regedit->vl, node->child_head->key); >+ WERROR rv; >+ >+ rv = tree_node_load_children(node); >+ if (W_ERROR_IS_OK(rv)) { >+ print_path(regedit, node->child_head); >+ tree_view_update(regedit->keys, node->child_head); >+ value_list_load(regedit->vl, node->child_head->key); >+ } else { >+ dialog_notice(regedit, DIA_ALERT, "Loading Subkeys", >+ "Failed to load subkeys."); >+ } > } > break; > case KEY_LEFT: >-- >2.1.1 > > >From 8e75d8add141ecae4a71235fe5df78aeffa0f5b6 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Wed, 25 Jun 2014 21:55:27 -0700 >Subject: [PATCH 15/45] regedit: include error description in popups > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit df36fe7998fee3fc22976aeb42c25e2a2f0d73c5) >--- > source3/utils/regedit.c | 9 ++++++--- > 1 file changed, 6 insertions(+), 3 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 7a47db2..2b32e94 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -236,8 +236,9 @@ static void add_reg_key(struct regedit *regedit, struct tree_node *node, > tree_view_clear(regedit->keys); > tree_view_update(regedit->keys, list); > } else { >+ msg = get_friendly_werror_msg(rv); > dialog_notice(regedit, DIA_ALERT, "New Key", >- "Failed to create key."); >+ "Failed to create key: %s", msg); > } > talloc_free(discard_const(name)); > } >@@ -369,8 +370,9 @@ static void handle_tree_input(struct regedit *regedit, int c) > tree_view_update(regedit->keys, node->child_head); > value_list_load(regedit->vl, node->child_head->key); > } else { >+ const char *msg = get_friendly_werror_msg(rv); > dialog_notice(regedit, DIA_ALERT, "Loading Subkeys", >- "Failed to load subkeys."); >+ "Failed to load subkeys: %s", msg); > } > } > break; >@@ -423,8 +425,9 @@ static void handle_tree_input(struct regedit *regedit, int c) > tree_view_update(regedit->keys, node); > value_list_load(regedit->vl, node->key); > } else { >+ const char *msg = get_friendly_werror_msg(rv); > dialog_notice(regedit, DIA_ALERT, "Delete Key", >- "Failed to delete key."); >+ "Failed to delete key: %s", msg); > } > } > break; >-- >2.1.1 > > >From 7b4932b60c2cb5c50b571b55de2207d861e5643f Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Wed, 25 Jun 2014 22:29:06 -0700 >Subject: [PATCH 16/45] regedit: don't fail loading keys if just a few are > unavailable > >Sometimes a key might fail to open due to access restrictions. >Only report failure if all keys failed to be opened. > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit aba2b04b6c5584db63d03adab57fe1fd12ee71b4) >--- > source3/utils/regedit_treeview.c | 27 +++++++++++++++------------ > 1 file changed, 15 insertions(+), 12 deletions(-) > >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index 9962ad9..c8a6596 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -179,7 +179,7 @@ WERROR tree_node_load_children(struct tree_node *node) > struct registry_key *key; > const char *key_name, *klass; > NTTIME modified; >- uint32_t i, nsubkeys; >+ uint32_t i, nsubkeys, count; > WERROR rv; > struct tree_node *prev, **array; > >@@ -196,7 +196,7 @@ WERROR tree_node_load_children(struct tree_node *node) > return WERR_NOMEM; > } > >- for (i = 0; i < nsubkeys; ++i) { >+ for (count = 0, i = 0; i < nsubkeys; ++i) { > rv = reg_key_get_subkey_by_index(node, node->key, i, > &key_name, &klass, > &modified); >@@ -206,25 +206,28 @@ WERROR tree_node_load_children(struct tree_node *node) > > rv = reg_open_key(node, node->key, key_name, &key); > if (!W_ERROR_IS_OK(rv)) { >- goto finish; >+ continue; > } > >- array[i] = tree_node_new(node, node, key_name, key); >- if (array[i] == NULL) { >+ array[count] = tree_node_new(node, node, key_name, key); >+ if (array[count] == NULL) { > rv = WERR_NOMEM; > goto finish; > } >+ ++count; > } > >- TYPESAFE_QSORT(array, nsubkeys, node_cmp); >+ if (count) { >+ TYPESAFE_QSORT(array, count, node_cmp); > >- for (i = 1, prev = array[0]; i < nsubkeys; ++i) { >- tree_node_append(prev, array[i]); >- prev = array[i]; >- } >- node->child_head = array[0]; >+ for (i = 1, prev = array[0]; i < count; ++i) { >+ tree_node_append(prev, array[i]); >+ prev = array[i]; >+ } >+ node->child_head = array[0]; > >- rv = WERR_OK; >+ rv = WERR_OK; >+ } > > finish: > if (!W_ERROR_IS_OK(rv)) { >-- >2.1.1 > > >From 34292323dce0b0d740da9230f69aacf79f2ce5db Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Wed, 25 Jun 2014 22:51:27 -0700 >Subject: [PATCH 17/45] regedit: set cursor to the parent node when ascending > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit baf491ff0bdb40520d8a093e5c08c8608ed3075a) >--- > source3/utils/regedit.c | 5 +++-- > 1 file changed, 3 insertions(+), 2 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 2b32e94..8b2a35d 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -380,8 +380,9 @@ static void handle_tree_input(struct regedit *regedit, int c) > node = tree_view_get_current_node(regedit->keys); > if (node && node->parent) { > print_path(regedit, node->parent); >- node = tree_node_first(node->parent); >- tree_view_update(regedit->keys, node); >+ node = node->parent; >+ tree_view_update(regedit->keys, tree_node_first(node)); >+ tree_view_set_current_node(regedit->keys, node); > value_list_load(regedit->vl, node->key); > } > break; >-- >2.1.1 > > >From bacd2285185aaa3e58e3c62686f7e150577063b7 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Thu, 26 Jun 2014 07:51:22 -0700 >Subject: [PATCH 18/45] regedit: set cursor after creating a new key > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 2a8beb99a49829adfbad1c887448e3a2caa32255) >--- > source3/utils/regedit.c | 4 ++++ > 1 file changed, 4 insertions(+) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 8b2a35d..471f875 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -235,6 +235,10 @@ static void add_reg_key(struct regedit *regedit, struct tree_node *node, > list = tree_node_first(node); > tree_view_clear(regedit->keys); > tree_view_update(regedit->keys, list); >+ if (!subkey) { >+ node = new_node; >+ } >+ tree_view_set_current_node(regedit->keys, node); > } else { > msg = get_friendly_werror_msg(rv); > dialog_notice(regedit, DIA_ALERT, "New Key", >-- >2.1.1 > > >From b0ada6d626f68029a2488f3f334d7bff9ee6039f Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Fri, 27 Jun 2014 18:01:36 -0700 >Subject: [PATCH 19/45] regedit: reopen parent keys when adding or removing > subkeys > >This clears any cache associated with the parent key, >and ensures the changes will be noticed by the UI. > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 75045f052a5bc00fc8ffe35514c60e2f1611c9e9) >--- > source3/utils/regedit.c | 5 +++++ > source3/utils/regedit_treeview.c | 9 +++++++++ > source3/utils/regedit_treeview.h | 1 + > 3 files changed, 15 insertions(+) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 471f875..b006fac 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -230,6 +230,10 @@ static void add_reg_key(struct regedit *regedit, struct tree_node *node, > name, new_key); > SMB_ASSERT(new_node); > tree_node_insert_sorted(list, new_node); >+ } else { >+ /* Reopen the parent key to make sure the >+ new subkey will be noticed. */ >+ tree_node_reopen_key(parent); > } > > list = tree_node_first(node); >@@ -419,6 +423,7 @@ static void handle_tree_input(struct regedit *regedit, int c) > > rv = reg_key_del(node, parent->key, node->name); > if (W_ERROR_IS_OK(rv)) { >+ tree_node_reopen_key(parent); > tree_view_clear(regedit->keys); > pop = tree_node_pop(&node); > tree_node_free_recursive(pop); >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index c8a6596..3af3c8b 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -141,6 +141,15 @@ static uint32_t get_num_subkeys(struct tree_node *node) > return 0; > } > >+WERROR tree_node_reopen_key(struct tree_node *node) >+{ >+ SMB_ASSERT(node->parent != NULL); >+ SMB_ASSERT(node->name != NULL); >+ TALLOC_FREE(node->key); >+ return reg_open_key(node->parent, node->parent->key, node->name, >+ &node->key); >+} >+ > bool tree_node_has_children(struct tree_node *node) > { > if (node->child_head) { >diff --git a/source3/utils/regedit_treeview.h b/source3/utils/regedit_treeview.h >index cd17a3c..954bae5 100644 >--- a/source3/utils/regedit_treeview.h >+++ b/source3/utils/regedit_treeview.h >@@ -66,6 +66,7 @@ void tree_view_resize(struct tree_view *view, int nlines, int ncols, > void tree_view_show(struct tree_view *view); > void tree_view_clear(struct tree_view *view); > WERROR tree_view_update(struct tree_view *view, struct tree_node *list); >+WERROR tree_node_reopen_key(struct tree_node *node); > bool tree_node_has_children(struct tree_node *node); > WERROR tree_node_load_children(struct tree_node *node); > void tree_node_insert_sorted(struct tree_node *list, struct tree_node *node); >-- >2.1.1 > > >From 25cf42caf2d5e0157f7adacc6c5ab40ba8531003 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Fri, 27 Jun 2014 19:33:03 -0700 >Subject: [PATCH 20/45] regedit: reopen key after editing or removing values > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 5732d3f01284a0080740f1cb69c91cf4893fb401) >--- > source3/utils/regedit.c | 3 +++ > 1 file changed, 3 insertions(+) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index b006fac..9b8a7dd 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -472,6 +472,7 @@ static void handle_value_input(struct regedit *regedit, int c) > node = tree_view_get_current_node(regedit->keys); > dialog_edit_value(regedit, node->key, vitem->type, > vitem, binmode); >+ tree_node_reopen_key(node); > value_list_load(regedit->vl, node->key); > } > break; >@@ -486,6 +487,7 @@ static void handle_value_input(struct regedit *regedit, int c) > node = tree_view_get_current_node(regedit->keys); > dialog_edit_value(regedit, node->key, new_type, NULL, > false); >+ tree_node_reopen_key(node); > value_list_load(regedit->vl, node->key); > } > break; >@@ -505,6 +507,7 @@ static void handle_value_input(struct regedit *regedit, int c) > node = tree_view_get_current_node(regedit->keys); > reg_del_value(regedit, node->key, > vitem->value_name); >+ tree_node_reopen_key(node); > value_list_load(regedit->vl, node->key); > } > } >-- >2.1.1 > > >From 62a7e2b92432afb08a74c2dd169d782cb2f161bb Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Mon, 30 Jun 2014 23:14:20 -0700 >Subject: [PATCH 21/45] regedit: add a refresh command to clear cache and > reload current path > >This is needed to view changes made externally > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >(cherry picked from commit 41d5112407d7426d75671ac6967e62b080f63857) >--- > source3/utils/regedit.c | 32 +++++++++++++--- > source3/utils/regedit_treeview.c | 83 ++++++++++++++++++++++++++++++++++++---- > source3/utils/regedit_treeview.h | 4 +- > 3 files changed, 104 insertions(+), 15 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 9b8a7dd..c0dbf90 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -52,6 +52,7 @@ > #define PATH_WIDTH_MAX 1024 > > struct regedit { >+ struct registry_context *registry_context; > WINDOW *main_window; > WINDOW *path_label; > size_t path_len; >@@ -86,8 +87,7 @@ static void print_path(struct regedit *regedit, struct tree_node *node) > } > > /* load all available hives */ >-static struct tree_node *load_hives(TALLOC_CTX *mem_ctx, >- struct registry_context *ctx) >+static struct tree_node *load_hives(struct regedit *regedit) > { > const char *hives[] = { > "HKEY_CLASSES_ROOT", >@@ -110,12 +110,13 @@ static struct tree_node *load_hives(TALLOC_CTX *mem_ctx, > prev = NULL; > > for (i = 0; hives[i] != NULL; ++i) { >- rv = reg_get_predefined_key_by_name(ctx, hives[i], &key); >+ rv = reg_get_predefined_key_by_name(regedit->registry_context, >+ hives[i], &key); > if (!W_ERROR_IS_OK(rv)) { > continue; > } > >- node = tree_node_new(mem_ctx, NULL, hives[i], key); >+ node = tree_node_new(regedit, NULL, hives[i], key); > if (node == NULL) { > return NULL; > } >@@ -426,7 +427,7 @@ static void handle_tree_input(struct regedit *regedit, int c) > tree_node_reopen_key(parent); > tree_view_clear(regedit->keys); > pop = tree_node_pop(&node); >- tree_node_free_recursive(pop); >+ talloc_free(pop); > node = parent->child_head; > if (node == NULL) { > node = tree_node_first(parent); >@@ -530,6 +531,24 @@ static bool find_substring_nocase(const char *haystack, const char *needle) > static void handle_main_input(struct regedit *regedit, int c) > { > switch (c) { >+ case 18: { /* CTRL-R */ >+ struct tree_node *root, *node; >+ const char **path; >+ >+ node = tree_view_get_current_node(regedit->keys); >+ path = tree_node_get_path(regedit, node); >+ >+ root = load_hives(regedit); >+ tree_view_set_root(regedit->keys, root); >+ tree_view_set_path(regedit->keys, path); >+ node = tree_view_get_current_node(regedit->keys); >+ value_list_load(regedit->vl, node->key); >+ tree_view_show(regedit->keys); >+ value_list_show(regedit->vl); >+ print_path(regedit, node); >+ talloc_free(discard_const(path)); >+ break; >+ } > case 'f': > case 'F': > case '/': { >@@ -618,6 +637,7 @@ static void display_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx) > SMB_ASSERT(regedit != NULL); > regedit_main = regedit; > >+ regedit->registry_context = ctx; > regedit->main_window = stdscr; > keypad(regedit->main_window, TRUE); > >@@ -627,7 +647,7 @@ static void display_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx) > wprintw(regedit->path_label, "/"); > show_path(regedit_main); > >- root = load_hives(regedit, ctx); >+ root = load_hives(regedit); > SMB_ASSERT(root != NULL); > > regedit->keys = tree_view_new(regedit, root, KEY_HEIGHT, KEY_WIDTH, >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index 3af3c8b..2f44613 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -272,6 +272,44 @@ void tree_view_clear(struct tree_view *view) > multilist_set_data(view->list, NULL); > } > >+WERROR tree_view_set_root(struct tree_view *view, struct tree_node *root) >+{ >+ multilist_set_data(view->list, NULL); >+ talloc_free(view->root); >+ view->root = root; >+ return tree_view_update(view, root); >+} >+ >+WERROR tree_view_set_path(struct tree_view *view, const char **path) >+{ >+ struct tree_node *top, *node; >+ WERROR rv; >+ >+ top = view->root; >+ while (*path) { >+ for (node = top; node != NULL; node = node->next) { >+ if (strcmp(*path, node->name) == 0) { >+ if (path[1] && tree_node_has_children(node)) { >+ rv = tree_node_load_children(node); >+ if (!W_ERROR_IS_OK(rv)) { >+ return rv; >+ } >+ SMB_ASSERT(node->child_head); >+ top = node->child_head; >+ break; >+ } else { >+ tree_view_update(view, top); >+ tree_view_set_current_node(view, node); >+ return WERR_OK; >+ } >+ } >+ } >+ ++path; >+ } >+ >+ return WERR_OK; >+} >+ > WERROR tree_view_update(struct tree_view *view, struct tree_node *list) > { > WERROR rv; >@@ -476,20 +514,38 @@ void tree_view_resize(struct tree_view *view, int nlines, int ncols, > tree_view_show(view); > } > >-static void print_path_recursive(WINDOW *label, struct tree_node *node, >- size_t *len) >+const char **tree_node_get_path(TALLOC_CTX *ctx, struct tree_node *node) > { >- if (node->parent) >- print_path_recursive(label, node->parent, len); >+ const char **array; >+ size_t nitems, index; >+ struct tree_node *p; > >- wprintw(label, "%s/", node->name); >- *len += 1 + strlen(node->name); >+ for (nitems = 0, p = node; p != NULL; p = p->parent) { >+ ++nitems; >+ } >+ >+ array = talloc_zero_array(ctx, const char *, nitems + 1); >+ if (array == NULL) { >+ return NULL; >+ } >+ >+ for (index = nitems - 1, p = node; p != NULL; p = p->parent, --index) { >+ array[index] = talloc_strdup(array, p->name); >+ if (array[index] == NULL) { >+ talloc_free(discard_const(array)); >+ return NULL; >+ } >+ } >+ >+ return array; > } > > /* print the path of node to label */ > size_t tree_node_print_path(WINDOW *label, struct tree_node *node) > { > size_t len = 1; >+ const char **path; >+ TALLOC_CTX *frame; > > if (node == NULL) > return 0; >@@ -497,8 +553,19 @@ size_t tree_node_print_path(WINDOW *label, struct tree_node *node) > werase(label); > wprintw(label, "/"); > >- if (node->parent) >- print_path_recursive(label, node->parent, &len); >+ if (node->parent == NULL) >+ return 0; >+ >+ frame = talloc_stackframe(); >+ path = tree_node_get_path(frame, node->parent); >+ >+ while (*path) { >+ len += strlen(*path) + 1; >+ wprintw(label, "%s/", *path); >+ ++path; >+ } >+ >+ talloc_free(frame); > > return len; > } >diff --git a/source3/utils/regedit_treeview.h b/source3/utils/regedit_treeview.h >index 954bae5..29c5fe2 100644 >--- a/source3/utils/regedit_treeview.h >+++ b/source3/utils/regedit_treeview.h >@@ -55,8 +55,8 @@ 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); > void tree_node_append_last(struct tree_node *list, struct tree_node *node); >-void tree_node_free_recursive(struct tree_node *list); > 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); > struct tree_view *tree_view_new(TALLOC_CTX *ctx, struct tree_node *root, > int nlines, int ncols, > int begin_y, int begin_x); >@@ -65,6 +65,8 @@ void tree_view_resize(struct tree_view *view, int nlines, int ncols, > int begin_y, int begin_x); > void tree_view_show(struct tree_view *view); > void tree_view_clear(struct tree_view *view); >+WERROR tree_view_set_root(struct tree_view *view, struct tree_node *root); >+WERROR tree_view_set_path(struct tree_view *view, const char **path); > WERROR tree_view_update(struct tree_view *view, struct tree_node *list); > WERROR tree_node_reopen_key(struct tree_node *node); > bool tree_node_has_children(struct tree_node *node); >-- >2.1.1 > > >From f5493178cae0d68195299cb257b9ec79588fdd1a Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Mon, 30 Jun 2014 23:19:53 -0700 >Subject: [PATCH 22/45] regedit: make all hives descend from a root node > >This helps simplify cleanup, since each node's talloc context is the >parent node, and freeing the root node will destroy the entire tree >without any extra utility functions. > >It also wouldn't be hard to extend this later on to support browsing >multiple registries at the same time. > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit f9a2f2eb7cc3c69f20ab615dd98b750414672fe3) >--- > source3/utils/regedit.c | 60 ++++----------------------- > source3/utils/regedit_treeview.c | 90 +++++++++++++++++++++++++++++----------- > source3/utils/regedit_treeview.h | 6 +++ > 3 files changed, 79 insertions(+), 77 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index c0dbf90..8fca96b 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -86,53 +86,6 @@ static void print_path(struct regedit *regedit, struct tree_node *node) > show_path(regedit); > } > >-/* load all available hives */ >-static struct tree_node *load_hives(struct regedit *regedit) >-{ >- const char *hives[] = { >- "HKEY_CLASSES_ROOT", >- "HKEY_CURRENT_USER", >- "HKEY_LOCAL_MACHINE", >- "HKEY_PERFORMANCE_DATA", >- "HKEY_USERS", >- "HKEY_CURRENT_CONFIG", >- "HKEY_DYN_DATA", >- "HKEY_PERFORMANCE_TEXT", >- "HKEY_PERFORMANCE_NLSTEXT", >- NULL >- }; >- struct tree_node *root, *prev, *node; >- struct registry_key *key; >- WERROR rv; >- size_t i; >- >- root = NULL; >- prev = NULL; >- >- for (i = 0; hives[i] != NULL; ++i) { >- rv = reg_get_predefined_key_by_name(regedit->registry_context, >- hives[i], &key); >- if (!W_ERROR_IS_OK(rv)) { >- continue; >- } >- >- node = tree_node_new(regedit, NULL, hives[i], key); >- if (node == NULL) { >- return NULL; >- } >- >- if (root == NULL) { >- root = node; >- } >- if (prev) { >- tree_node_append(prev, node); >- } >- prev = node; >- } >- >- return root; >-} >- > static void print_help(struct regedit *regedit) > { > const char *khelp = "[n] New Key [s] New Subkey [d] Del Key " >@@ -196,7 +149,7 @@ static void add_reg_key(struct regedit *regedit, struct tree_node *node, > const char *name; > const char *msg; > >- if (!subkey && !node->parent) { >+ if (!subkey && tree_node_is_top_level(node)) { > return; > } > >@@ -387,7 +340,7 @@ static void handle_tree_input(struct regedit *regedit, int c) > break; > case KEY_LEFT: > node = tree_view_get_current_node(regedit->keys); >- if (node && node->parent) { >+ if (node && !tree_node_is_top_level(node)) { > print_path(regedit, node->parent); > node = node->parent; > tree_view_update(regedit->keys, tree_node_first(node)); >@@ -410,7 +363,7 @@ static void handle_tree_input(struct regedit *regedit, int c) > int sel; > > node = tree_view_get_current_node(regedit->keys); >- if (!node->parent) { >+ if (tree_node_is_top_level(node)) { > break; > } > sel = dialog_notice(regedit, DIA_CONFIRM, >@@ -537,8 +490,11 @@ static void handle_main_input(struct regedit *regedit, int c) > > node = tree_view_get_current_node(regedit->keys); > path = tree_node_get_path(regedit, node); >+ SMB_ASSERT(path != NULL); >+ >+ root = tree_node_new_root(regedit, regedit->registry_context); >+ SMB_ASSERT(root != NULL); > >- root = load_hives(regedit); > tree_view_set_root(regedit->keys, root); > tree_view_set_path(regedit->keys, path); > node = tree_view_get_current_node(regedit->keys); >@@ -647,7 +603,7 @@ static void display_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx) > wprintw(regedit->path_label, "/"); > show_path(regedit_main); > >- root = load_hives(regedit); >+ root = tree_node_new_root(regedit, ctx); > SMB_ASSERT(root != NULL); > > regedit->keys = tree_view_new(regedit, root, KEY_HEIGHT, KEY_WIDTH, >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index 2f44613..dd4b5cb 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -23,6 +23,12 @@ > > #define HEADING_X 3 > >+static int tree_node_free(struct tree_node *node) >+{ >+ DEBUG(9, ("tree_node_free('%s', %p)\n", node->name, node)); >+ return 0; >+} >+ > struct tree_node *tree_node_new(TALLOC_CTX *ctx, struct tree_node *parent, > const char *name, struct registry_key *key) > { >@@ -32,6 +38,8 @@ struct tree_node *tree_node_new(TALLOC_CTX *ctx, struct tree_node *parent, > if (!node) { > return NULL; > } >+ talloc_set_destructor(node, tree_node_free); >+ DEBUG(9, ("tree_node_new('%s', %p)\n", name, node)); > > node->name = talloc_strdup(node, name); > if (!node->name) { >@@ -39,7 +47,9 @@ struct tree_node *tree_node_new(TALLOC_CTX *ctx, struct tree_node *parent, > return NULL; > } > >- node->key = talloc_steal(node, key); >+ if (key) { >+ node->key = talloc_steal(node, key); >+ } > > if (parent) { > /* Check if this node is the first descendant of parent. */ >@@ -52,6 +62,52 @@ struct tree_node *tree_node_new(TALLOC_CTX *ctx, struct tree_node *parent, > return node; > } > >+/* prepare a root node with all available hives as children */ >+struct tree_node *tree_node_new_root(TALLOC_CTX *ctx, >+ struct registry_context *regctx) >+{ >+ const char *hives[] = { >+ "HKEY_CLASSES_ROOT", >+ "HKEY_CURRENT_USER", >+ "HKEY_LOCAL_MACHINE", >+ "HKEY_PERFORMANCE_DATA", >+ "HKEY_USERS", >+ "HKEY_CURRENT_CONFIG", >+ "HKEY_DYN_DATA", >+ "HKEY_PERFORMANCE_TEXT", >+ "HKEY_PERFORMANCE_NLSTEXT", >+ NULL >+ }; >+ struct tree_node *root, *prev, *node; >+ struct registry_key *key; >+ WERROR rv; >+ size_t i; >+ >+ root = tree_node_new(ctx, NULL, "ROOT", NULL); >+ if (root == NULL) { >+ return NULL; >+ } >+ prev = NULL; >+ >+ for (i = 0; hives[i] != NULL; ++i) { >+ rv = reg_get_predefined_key_by_name(regctx, hives[i], &key); >+ if (!W_ERROR_IS_OK(rv)) { >+ continue; >+ } >+ >+ node = tree_node_new(root, root, hives[i], key); >+ if (node == NULL) { >+ return NULL; >+ } >+ if (prev) { >+ tree_node_append(prev, node); >+ } >+ prev = node; >+ } >+ >+ return root; >+} >+ > void tree_node_append(struct tree_node *left, struct tree_node *right) > { > if (left->next) { >@@ -250,23 +306,6 @@ finish: > return rv; > } > >-void tree_node_free_recursive(struct tree_node *list) >-{ >- struct tree_node *node; >- >- if (list == NULL) { >- return; >- } >- >- while ((node = tree_node_pop(&list)) != NULL) { >- if (node->child_head) { >- tree_node_free_recursive(node->child_head); >- } >- node->child_head = NULL; >- talloc_free(node); >- } >-} >- > void tree_view_clear(struct tree_view *view) > { > multilist_set_data(view->list, NULL); >@@ -277,7 +316,7 @@ WERROR tree_view_set_root(struct tree_view *view, struct tree_node *root) > multilist_set_data(view->list, NULL); > talloc_free(view->root); > view->root = root; >- return tree_view_update(view, root); >+ return tree_view_update(view, root->child_head); > } > > WERROR tree_view_set_path(struct tree_view *view, const char **path) >@@ -285,7 +324,7 @@ WERROR tree_view_set_path(struct tree_view *view, const char **path) > struct tree_node *top, *node; > WERROR rv; > >- top = view->root; >+ top = view->root->child_head; > while (*path) { > for (node = top; node != NULL; node = node->next) { > if (strcmp(*path, node->name) == 0) { >@@ -377,7 +416,6 @@ static int tree_view_free(struct tree_view *view) > if (view->window) { > delwin(view->window); > } >- tree_node_free_recursive(view->root); > > return 0; > } >@@ -479,7 +517,7 @@ struct tree_view *tree_view_new(TALLOC_CTX *ctx, struct tree_node *root, > if (view->list == NULL) { > goto fail; > } >- tree_view_update(view, root); >+ tree_view_update(view, root->child_head); > > return view; > >@@ -520,7 +558,7 @@ const char **tree_node_get_path(TALLOC_CTX *ctx, struct tree_node *node) > size_t nitems, index; > struct tree_node *p; > >- for (nitems = 0, p = node; p != NULL; p = p->parent) { >+ for (nitems = 0, p = node; !tree_node_is_root(p); p = p->parent) { > ++nitems; > } > >@@ -529,7 +567,9 @@ const char **tree_node_get_path(TALLOC_CTX *ctx, struct tree_node *node) > return NULL; > } > >- for (index = nitems - 1, p = node; p != NULL; p = p->parent, --index) { >+ for (index = nitems - 1, p = node; >+ !tree_node_is_root(p); >+ p = p->parent, --index) { > array[index] = talloc_strdup(array, p->name); > if (array[index] == NULL) { > talloc_free(discard_const(array)); >@@ -553,7 +593,7 @@ size_t tree_node_print_path(WINDOW *label, struct tree_node *node) > werase(label); > wprintw(label, "/"); > >- if (node->parent == NULL) >+ if (tree_node_is_top_level(node)) > return 0; > > frame = talloc_stackframe(); >diff --git a/source3/utils/regedit_treeview.h b/source3/utils/regedit_treeview.h >index 29c5fe2..4d1851a 100644 >--- a/source3/utils/regedit_treeview.h >+++ b/source3/utils/regedit_treeview.h >@@ -48,8 +48,14 @@ struct tree_view { > struct multilist *list; > }; > >+struct registry_context; >+ > struct tree_node *tree_node_new(TALLOC_CTX *ctx, struct tree_node *parent, > const char *name, struct registry_key *key); >+struct tree_node *tree_node_new_root(TALLOC_CTX *ctx, >+ struct registry_context *regctx); >+#define tree_node_is_root(node) ((node)->key == NULL) >+#define tree_node_is_top_level(node) tree_node_is_root((node)->parent) > 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); >-- >2.1.1 > > >From 870d1ed5dc064ef23df50ad36588f15cb0088905 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Tue, 1 Jul 2014 16:00:16 -0700 >Subject: [PATCH 23/45] regedit: add a panic handler to restore terminal > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit fec275a4a8e9ecd77fb30c4a242a2fe832d9f41c) >--- > source3/utils/regedit.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 8fca96b..5b7885c 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -567,6 +567,12 @@ int regedit_getch(void) > return c; > } > >+static void regedit_panic_handler(const char *msg) >+{ >+ endwin(); >+ smb_panic_s3(msg); >+} >+ > static void display_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx) > { > struct regedit *regedit; >@@ -579,6 +585,8 @@ static void display_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx) > cbreak(); > noecho(); > >+ fault_configure(regedit_panic_handler); >+ > colors = has_colors(); > if (colors) { > start_color(); >-- >2.1.1 > > >From b456047d21919bfcbd19796107efdc7eae6c32eb Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Mon, 7 Jul 2014 21:30:49 -0700 >Subject: [PATCH 24/45] regedit: simplify cleanup after loading children > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit c94c765f01dc145ee7f1abfe1379ed9c923f3d43) >--- > source3/utils/regedit_treeview.c | 11 +++-------- > 1 file changed, 3 insertions(+), 8 deletions(-) > >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index dd4b5cb..47d9282 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -274,7 +274,7 @@ WERROR tree_node_load_children(struct tree_node *node) > continue; > } > >- array[count] = tree_node_new(node, node, key_name, key); >+ array[count] = tree_node_new(array, node, key_name, key); > if (array[count] == NULL) { > rv = WERR_NOMEM; > goto finish; >@@ -286,21 +286,16 @@ WERROR tree_node_load_children(struct tree_node *node) > TYPESAFE_QSORT(array, count, node_cmp); > > for (i = 1, prev = array[0]; i < count; ++i) { >+ talloc_steal(node, array[i]); > tree_node_append(prev, array[i]); > prev = array[i]; > } >- node->child_head = array[0]; >+ node->child_head = talloc_steal(node, array[0]); > > rv = WERR_OK; > } > > finish: >- if (!W_ERROR_IS_OK(rv)) { >- for (i = 0; i < nsubkeys; ++i) { >- talloc_free(array[i]); >- } >- node->child_head = NULL; >- } > talloc_free(array); > > return rv; >-- >2.1.1 > > >From a8f3c0407e4cc3f074a52a673e94cdefb889a886 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Fri, 18 Jul 2014 13:35:14 -0700 >Subject: [PATCH 25/45] regedit: add padding to fit REG_MULTI_SZ to the text > field > >This fixes a bug loading REG_MULTI_SZ values into the editor dialog, >since ncurses fields don't handle newline characters. > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 42df2e643f68f5ec19e6a41eade29199a3266035) >--- > source3/utils/regedit_dialog.c | 29 +++++++++++++++++++++-------- > 1 file changed, 21 insertions(+), 8 deletions(-) > >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index 944fcc8..ce67065 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -642,22 +642,35 @@ static WERROR fill_value_buffer(struct edit_dialog *edit, > break; > } > case REG_MULTI_SZ: { >- const char **p, **a; >+ int rows, cols, max; >+ size_t padding, length, index; >+ const char **array, **arrayp; > char *buf = NULL; > >- if (!pull_reg_multi_sz(edit, &vitem->data, &a)) { >+ dynamic_field_info(edit->field[FLD_DATA], &rows, &cols, &max); >+ if (!pull_reg_multi_sz(edit, &vitem->data, &array)) { > return WERR_NOMEM; > } >- for (p = a; *p != NULL; ++p) { >- if (buf == NULL) { >- buf = talloc_asprintf(edit, "%s\n", *p); >- } else { >- buf = talloc_asprintf_append(buf, "%s\n", *p); >- } >+ >+ /* try to fit each string on it's own line. each line >+ needs to be padded with whitespace manually, since >+ ncurses fields do not have newlines. */ >+ for (index = 0, arrayp = array; *arrayp != NULL; ++arrayp) { >+ length = MIN(strlen(*arrayp), cols); >+ padding = cols - length; >+ buf = talloc_realloc(edit, buf, char, >+ talloc_array_length(buf) + >+ length + padding + 1); > if (buf == NULL) { > return WERR_NOMEM; > } >+ memcpy(&buf[index], *arrayp, length); >+ index += length; >+ memset(&buf[index], ' ', padding); >+ index += padding; >+ buf[index] = '\0'; > } >+ > set_field_buffer(edit->field[FLD_DATA], 0, buf); > talloc_free(buf); > } >-- >2.1.1 > > >From 6bdd7c00076f68cc972836ef169a31be24cf9661 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Fri, 25 Jul 2014 23:16:52 -0700 >Subject: [PATCH 26/45] regedit: improvements for hexedit > >This mainly enables setting the hexedit buffer after the editor is >allocated. > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 30ae8f1014122258ff3b9415370fc679675929de) >--- > source3/utils/regedit_hexedit.c | 82 +++++++++++++++++++++++++++++++++++------ > source3/utils/regedit_hexedit.h | 30 ++------------- > 2 files changed, 74 insertions(+), 38 deletions(-) > >diff --git a/source3/utils/regedit_hexedit.c b/source3/utils/regedit_hexedit.c >index 8f1c2c7..847c5d8 100644 >--- a/source3/utils/regedit_hexedit.c >+++ b/source3/utils/regedit_hexedit.c >@@ -20,6 +20,33 @@ > #include "includes.h" > #include "regedit_hexedit.h" > >+/* >+ offset hex1 hex2 ascii >+ 00000000 FF FF FF FF FF FF FF FF ........ >+*/ >+ >+#define HEX_COL1 10 >+#define HEX_COL1_END 21 >+#define HEX_COL2 23 >+#define HEX_COL2_END 34 >+#define ASCII_COL 36 >+#define ASCII_COL_END LINE_WIDTH >+#define BYTES_PER_LINE 8 >+ >+struct hexedit { >+ size_t offset; >+ size_t len; >+ size_t alloc_size; >+ int cursor_y; >+ int cursor_x; >+ size_t cursor_offset; >+ size_t cursor_line_offset; >+ int nibble; >+ uint8_t *data; >+ WINDOW *win; >+ WINDOW *status_line; >+}; >+ > static int max_rows(WINDOW *win) > { > int maxy, maxx; >@@ -44,6 +71,7 @@ static int hexedit_free(struct hexedit *buf) > struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines, > int y, int x, const void *data, size_t sz) > { >+ WERROR rv; > struct hexedit *buf; > > buf = talloc_zero(ctx, struct hexedit); >@@ -53,22 +81,10 @@ struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines, > > talloc_set_destructor(buf, hexedit_free); > >- buf->data = talloc_zero_array(buf, uint8_t, sz); >- if (buf->data == NULL) { >- goto fail; >- } >- >- if (data) { >- memcpy(buf->data, data, sz); >- } >- >- buf->len = sz; >- buf->alloc_size = sz; > buf->win = derwin(parent, nlines, LINE_WIDTH, y, x); > if (buf->win == NULL) { > goto fail; > } >- buf->cursor_x = HEX_COL1; > > buf->status_line = derwin(buf->win, 1, LINE_WIDTH, max_rows(buf->win), > 0); >@@ -77,6 +93,11 @@ struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines, > } > wattron(buf->status_line, A_REVERSE | A_STANDOUT); > >+ rv = hexedit_set_buf(buf, data, sz); >+ if (!W_ERROR_IS_OK(rv)) { >+ goto fail; >+ } >+ > return buf; > > fail: >@@ -85,6 +106,40 @@ fail: > return NULL; > } > >+WERROR hexedit_set_buf(struct hexedit *buf, const void *data, size_t sz) >+{ >+ TALLOC_FREE(buf->data); >+ >+ buf->data = talloc_zero_array(buf, uint8_t, sz); >+ if (buf->data == NULL) { >+ return WERR_NOMEM; >+ } >+ >+ if (data != NULL) { >+ memcpy(buf->data, data, sz); >+ } >+ >+ buf->len = sz; >+ buf->alloc_size = sz; >+ buf->cursor_x = HEX_COL1; >+ buf->cursor_y = 0; >+ buf->cursor_offset = 0; >+ buf->cursor_line_offset = 0; >+ buf->nibble = 0; >+ >+ return WERR_OK; >+} >+ >+const void *hexedit_get_buf(struct hexedit *buf) >+{ >+ return buf->data; >+} >+ >+size_t hexedit_get_buf_len(struct hexedit *buf) >+{ >+ return buf->len; >+} >+ > static size_t bytes_per_screen(WINDOW *win) > { > return max_rows(win) * BYTES_PER_LINE; >@@ -103,6 +158,7 @@ void hexedit_set_cursor(struct hexedit *buf) > wcursyncup(buf->win); > wsyncup(buf->win); > untouchwin(buf->win); >+ wnoutrefresh(buf->status_line); > } > > void hexedit_refresh(struct hexedit *buf) >@@ -417,6 +473,8 @@ void hexedit_driver(struct hexedit *buf, int c) > do_edit(buf, c & 0xff); > break; > } >+ >+ hexedit_set_cursor(buf); > } > > WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz) >diff --git a/source3/utils/regedit_hexedit.h b/source3/utils/regedit_hexedit.h >index f0424cd..af2432a 100644 >--- a/source3/utils/regedit_hexedit.h >+++ b/source3/utils/regedit_hexedit.h >@@ -31,36 +31,14 @@ enum { > HE_CURSOR_PGDN = 0x1500 > }; > >-/* >- offset hex1 hex2 ascii >- 00000000 FF FF FF FF FF FF FF FF ........ >-*/ >- > #define LINE_WIDTH 44 >-#define HEX_COL1 10 >-#define HEX_COL1_END 21 >-#define HEX_COL2 23 >-#define HEX_COL2_END 34 >-#define ASCII_COL 36 >-#define ASCII_COL_END LINE_WIDTH >-#define BYTES_PER_LINE 8 >- >-struct hexedit { >- size_t offset; >- size_t len; >- size_t alloc_size; >- int cursor_y; >- int cursor_x; >- size_t cursor_offset; >- size_t cursor_line_offset; >- int nibble; >- uint8_t *data; >- WINDOW *win; >- WINDOW *status_line; >-}; >+struct hexedit; > > struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines, > int y, int x, const void *data, size_t sz); >+WERROR hexedit_set_buf(struct hexedit *buf, const void *data, size_t sz); >+const void *hexedit_get_buf(struct hexedit *buf); >+size_t hexedit_get_buf_len(struct hexedit *buf); > void hexedit_set_cursor(struct hexedit *buf); > void hexedit_refresh(struct hexedit *buf); > void hexedit_driver(struct hexedit *buf, int c); >-- >2.1.1 > > >From 6237284cc06fb65fb274d047b29907d5ece4a9e3 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Fri, 25 Jul 2014 23:26:27 -0700 >Subject: [PATCH 27/45] regedit: Introduce a new API to build the dialogs. > >This helps make new dialogs easier to create, because it provides some >common building blocks and a consistent way to deal with user input. > >Dialogs are divided into sections that stack vertically, and common >sections for typical UI things like text boxes, option lists, and >buttons are provided. > >The old dialogs are rewritten to use this API. > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit a728c391d7d4f6474e37f7118ba6df14dc9da6fd) >--- > source3/utils/regedit_dialog.c | 2544 ++++++++++++++++++++++++++-------------- > source3/utils/regedit_dialog.h | 186 ++- > 2 files changed, 1838 insertions(+), 892 deletions(-) > >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index ce67065..119219d 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -55,31 +55,19 @@ static char *string_trim(TALLOC_CTX *ctx, const char *buf) > > static int dialog_free(struct dialog *dia) > { >- if (dia->window) { >- delwin(dia->window); >- } >- if (dia->sub_window) { >- delwin(dia->sub_window); >- } >- if (dia->panel) { >- del_panel(dia->panel); >- } >- if (dia->choices) { >- unpost_menu(dia->choices); >- free_menu(dia->choices); >- } >- if (dia->choice_items) { >- ITEM **it; >- for (it = dia->choice_items; *it != NULL; ++it) { >- free_item(*it); >- } >- } >+ dialog_destroy(dia); > > return 0; > } > >-struct dialog *dialog_new(TALLOC_CTX *ctx, const char *title, int nlines, >- int ncols, int y, int x) >+static bool default_validator(struct dialog *dia, struct dialog_section *sect, >+ void *arg) >+{ >+ return true; >+} >+ >+struct dialog *dialog_new(TALLOC_CTX *ctx, short color, const char *title, >+ int y, int x) > { > struct dialog *dia; > >@@ -90,24 +78,14 @@ struct dialog *dialog_new(TALLOC_CTX *ctx, const char *title, int nlines, > > talloc_set_destructor(dia, dialog_free); > >- dia->window = newwin(nlines, ncols, y, x); >- if (dia->window == NULL) { >- goto fail; >- } >- >- box(dia->window, 0, 0); >- mvwaddstr(dia->window, 0, 1, title); >- >- /* body of the dialog within the box outline */ >- dia->sub_window = derwin(dia->window, nlines - 2, ncols - 2, 1, 1); >- if (dia->sub_window == NULL) { >- goto fail; >- } >- >- dia->panel = new_panel(dia->window); >- if (dia->panel == NULL) { >+ dia->title = talloc_strdup(dia, title); >+ if (dia->title == NULL) { > goto fail; > } >+ dia->x = x; >+ dia->y = y; >+ dia->color = color; >+ dia->submit = default_validator; > > return dia; > >@@ -118,8 +96,13 @@ fail: > > } > >-static void center_dialog_above_window(int *nlines, int *ncols, >- int *y, int *x) >+void dialog_set_submit_cb(struct dialog *dia, dialog_submit_cb cb, void *arg) >+{ >+ dia->submit = cb; >+ dia->submit_arg = arg; >+} >+ >+static void center_above_window(int *nlines, int *ncols, int *y, int *x) > { > int centery, centerx; > >@@ -143,491 +126,1609 @@ static void center_dialog_above_window(int *nlines, int *ncols, > } > } > >-static int dialog_getch(struct dialog *dia) >+void dialog_section_destroy(struct dialog_section *section) > { >- int c; >+ if (section->ops->destroy) { >+ section->ops->destroy(section); >+ } >+ if (section->window) { >+ delwin(section->window); >+ section->window = NULL; >+ } >+} > >- c = regedit_getch(); >+void dialog_section_init(struct dialog_section *section, >+ const struct dialog_section_ops *ops, >+ int nlines, int ncols) >+{ >+ section->ops = ops; >+ section->nlines = nlines; >+ section->ncols = ncols; >+} > >- if (c == KEY_RESIZE) { >- int nlines, ncols, y, x; >+const char *dialog_section_get_name(struct dialog_section *section) >+{ >+ return section->name; >+} > >- getmaxyx(dia->window, nlines, ncols); >- getbegyx(dia->window, y, x); >- if (dia->centered) { >- center_dialog_above_window(&nlines, &ncols, &y, &x); >- } else { >- if (nlines + y > LINES) { >- if (nlines > LINES) { >- y = 0; >- } else { >- y = LINES - nlines; >- } >- } >- if (ncols + x > COLS) { >- if (ncols > COLS) { >- x = 0; >- } else { >- x = COLS - ncols; >- } >- } >+void dialog_section_set_name(struct dialog_section *section, const char *name) >+{ >+ TALLOC_FREE(section->name); >+ section->name = talloc_strdup(section, name); >+} >+ >+void dialog_section_set_justify(struct dialog_section *section, >+ enum section_justify justify) >+{ >+ section->justify = justify; >+} >+ >+/* append a section to the dialog's circular list */ >+void dialog_append_section(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ SMB_ASSERT(section != NULL); >+ >+ if (!dia->head_section) { >+ dia->head_section = section; >+ } >+ if (dia->tail_section) { >+ dia->tail_section->next = section; >+ } >+ section->prev = dia->tail_section; >+ section->next = dia->head_section; >+ dia->head_section->prev = section; >+ dia->tail_section = section; >+} >+ >+struct dialog_section *dialog_find_section(struct dialog *dia, const char *name) >+{ >+ struct dialog_section *section = dia->head_section; >+ >+ do { >+ if (section->name && strequal(section->name, name)) { >+ return section; > } >- move_panel(dia->panel, y, x); >- doupdate(); >+ section = section->next; >+ } while (section != dia->head_section); >+ >+ return NULL; >+} >+ >+static void section_on_input(struct dialog *dia, int c) >+{ >+ struct dialog_section *section = dia->current_section; >+ >+ if (!section->ops->on_input) { >+ return; > } >+ section->ops->on_input(dia, section, c); >+} > >- return c; >+static bool section_on_tab(struct dialog *dia) >+{ >+ struct dialog_section *section = dia->current_section; >+ >+ if (!section || !section->ops->on_tab) { >+ return false; >+ } >+ return section->ops->on_tab(dia, section); > } > >-struct dialog *dialog_center_new(TALLOC_CTX *ctx, const char *title, >- int nlines, int ncols) >+static bool section_on_btab(struct dialog *dia) > { >- struct dialog *dia; >- int y, x; >+ struct dialog_section *section = dia->current_section; >+ >+ if (!section || !section->ops->on_btab) { >+ return false; >+ } >+ return section->ops->on_btab(dia, section); >+} > >- center_dialog_above_window(&nlines, &ncols, &y, &x); >+static bool section_on_up(struct dialog *dia) >+{ >+ struct dialog_section *section = dia->current_section; > >- dia = dialog_new(ctx, title, nlines, ncols, y, x); >- if (dia) { >- dia->centered = true; >+ if (!section || !section->ops->on_up) { >+ return false; > } >+ return section->ops->on_up(dia, section); >+} > >- return dia; >+static bool section_on_down(struct dialog *dia) >+{ >+ struct dialog_section *section = dia->current_section; >+ >+ if (!section || !section->ops->on_down) { >+ return false; >+ } >+ return section->ops->on_down(dia, section); > } > >-struct dialog *dialog_choice_new(TALLOC_CTX *ctx, const char *title, >- const char **choices, int nlines, >- int ncols, int y, int x) >+static bool section_on_left(struct dialog *dia) > { >- size_t nchoices, i; >- struct dialog *dia; >+ struct dialog_section *section = dia->current_section; > >- dia = dialog_new(ctx, title, nlines, ncols, y, x); >- if (dia == NULL) { >- return NULL; >+ if (!section || !section->ops->on_left) { >+ return false; > } >+ return section->ops->on_left(dia, section); >+} > >- dia->menu_window = derwin(dia->sub_window, 1, ncols - 3, >- nlines - 3, 0); >- if (dia->menu_window == NULL) { >- goto fail; >+static bool section_on_right(struct dialog *dia) >+{ >+ struct dialog_section *section = dia->current_section; >+ >+ if (!section || !section->ops->on_right) { >+ return false; > } >+ return section->ops->on_right(dia, section); >+} > >- for (nchoices = 0; choices[nchoices] != NULL; ++nchoices) >- ; >- dia->choice_items = talloc_zero_array(dia, ITEM *, nchoices + 1); >- if (dia->choice_items == NULL) { >- goto fail; >+static enum dialog_action section_on_enter(struct dialog *dia) >+{ >+ struct dialog_section *section = dia->current_section; >+ >+ if (!section || !section->ops->on_enter) { >+ return DIALOG_OK; > } >- for (i = 0; i < nchoices; ++i) { >- char *desc = talloc_strdup(dia, choices[i]); >- if (desc == NULL) { >- goto fail; >- } >- dia->choice_items[i] = new_item(desc, desc); >- if (dia->choice_items[i] == NULL) { >- goto fail; >- } >- /* store choice index */ >- set_item_userptr(dia->choice_items[i], (void*)(uintptr_t)i); >+ return section->ops->on_enter(dia, section); >+} >+ >+static bool section_on_focus(struct dialog *dia, bool forward) >+{ >+ struct dialog_section *section = dia->current_section; >+ >+ if (!section->ops->on_focus) { >+ return false; > } >+ return section->ops->on_focus(dia, section, forward); >+} > >- dia->choices = new_menu(dia->choice_items); >- if (dia->choices == NULL) { >- goto fail; >+static void section_on_leave_focus(struct dialog *dia) >+{ >+ struct dialog_section *section = dia->current_section; >+ >+ if (section->ops->on_leave_focus) { >+ section->ops->on_leave_focus(dia, section); > } >+} > >- set_menu_format(dia->choices, 1, ncols); >- set_menu_win(dia->choices, dia->sub_window); >- set_menu_sub(dia->choices, dia->menu_window); >- menu_opts_off(dia->choices, O_SHOWDESC); >- set_menu_mark(dia->choices, "* "); >- post_menu(dia->choices); >- wmove(dia->sub_window, 0, 0); >+static void section_set_next_focus(struct dialog *dia) >+{ >+ section_on_leave_focus(dia); > >- return dia; >+ do { >+ dia->current_section = dia->current_section->next; >+ } while (!section_on_focus(dia, true)); >+} > >-fail: >- talloc_free(dia); >+static void section_set_previous_focus(struct dialog *dia) >+{ >+ section_on_leave_focus(dia); > >- return NULL; >+ do { >+ dia->current_section = dia->current_section->prev; >+ } while (!section_on_focus(dia, false)); > } > >-struct dialog *dialog_choice_center_new(TALLOC_CTX *ctx, const char *title, >- const char **choices, int nlines, >- int ncols) >+WERROR dialog_create(struct dialog *dia) > { >- int y, x; >- struct dialog *dia; >- center_dialog_above_window(&nlines, &ncols, &y, &x); >+ WERROR rv = WERR_OK; >+ int row, col; >+ int nlines, ncols; >+ struct dialog_section *section; > >- dia = dialog_choice_new(ctx, title, choices, nlines, ncols, y, x); >- if (dia) { >+ nlines = 0; >+ ncols = 0; >+ SMB_ASSERT(dia->head_section != NULL); >+ >+ /* calculate total size based on sections */ >+ section = dia->head_section; >+ do { >+ nlines += section->nlines; >+ ncols = MAX(ncols, section->ncols); >+ section = section->next; >+ } while (section != dia->head_section); >+ >+ /* fill in widths for sections that expand */ >+ section = dia->head_section; >+ do { >+ if (section->ncols < 0) { >+ section->ncols = ncols; >+ } >+ section = section->next; >+ } while (section != dia->head_section); >+ >+ /* create window for dialog */ >+ nlines += 4; >+ ncols += 6; >+ dia->centered = false; >+ if (dia->y < 0 || dia->x < 0) { > dia->centered = true; >+ center_above_window(&nlines, &ncols, &dia->y, &dia->x); >+ } >+ dia->window = newwin(nlines, ncols, dia->y, dia->x); >+ if (dia->window == NULL) { >+ rv = WERR_NOMEM; >+ goto fail; >+ } >+ dia->panel = new_panel(dia->window); >+ if (dia->panel == NULL) { >+ rv = WERR_NOMEM; >+ goto fail; > } > >- return dia; >+ /* setup color and border */ >+ wbkgdset(dia->window, ' ' | COLOR_PAIR(dia->color)); >+ wclear(dia->window); >+ mvwhline(dia->window, 1, 2, 0, ncols - 4); >+ mvwhline(dia->window, nlines - 2, 2, 0, ncols - 4); >+ mvwvline(dia->window, 2, 1, 0, nlines - 4); >+ mvwvline(dia->window, 2, ncols - 2, 0, nlines - 4); >+ mvwaddch(dia->window, 1, 1, ACS_ULCORNER); >+ mvwaddch(dia->window, 1, ncols - 2, ACS_URCORNER); >+ mvwaddch(dia->window, nlines - 2, 1, ACS_LLCORNER); >+ mvwaddch(dia->window, nlines - 2, ncols - 2, ACS_LRCORNER); >+ col = ncols / 2 - MIN(strlen(dia->title) + 2, ncols) / 2; >+ mvwprintw(dia->window, 1, col, " %s ", dia->title); >+ >+ /* create subwindows for each section */ >+ row = 2; >+ section = dia->head_section; >+ do { >+ col = 3; >+ >+ switch (section->justify) { >+ case SECTION_JUSTIFY_LEFT: >+ break; >+ case SECTION_JUSTIFY_CENTER: >+ col += (ncols - 6)/ 2 - section->ncols / 2; >+ break; >+ case SECTION_JUSTIFY_RIGHT: >+ break; >+ } >+ >+ section->window = derwin(dia->window, section->nlines, >+ section->ncols, row, col); >+ if (section->window == NULL) { >+ rv = WERR_NOMEM; >+ goto fail; >+ } >+ SMB_ASSERT(section->ops->create != NULL); >+ rv = section->ops->create(dia, section); >+ row += section->nlines; >+ section = section->next; >+ } while (section != dia->head_section && W_ERROR_IS_OK(rv)); >+ >+ dia->current_section = dia->head_section; >+ section_set_next_focus(dia); >+ >+fail: >+ return rv; > } > >-static bool current_item_is_first(MENU *menu) >+void dialog_show(struct dialog *dia) > { >- const ITEM *it = current_item(menu); >+ struct dialog_section *section; > >- return item_index(it) == 0; >+ touchwin(dia->window); >+ wnoutrefresh(dia->window); >+ section = dia->head_section; >+ do { >+ wnoutrefresh(section->window); >+ section = section->next; >+ } while (section != dia->head_section); > } > >-static bool current_item_is_last(MENU *menu) >+void dialog_destroy(struct dialog *dia) > { >- const ITEM *it = current_item(menu); >+ struct dialog_section *section; > >- return item_index(it) == item_count(menu) - 1; >+ section = dia->head_section; >+ do { >+ dialog_section_destroy(section); >+ section = section->next; >+ } while (section != dia->head_section); >+ >+ if (dia->panel) { >+ del_panel(dia->panel); >+ dia->panel = NULL; >+ } >+ if (dia->window) { >+ delwin(dia->window); >+ dia->window = NULL; >+ } > } > >-static int handle_menu_input(MENU *menu, int c) >+static int dialog_getch(struct dialog *dia) > { >- ITEM *item; >+ int c; > >- switch (c) { >- case KEY_BTAB: >- if (current_item_is_first(menu)) { >- menu_driver(menu, REQ_LAST_ITEM); >- } else { >- menu_driver(menu, REQ_LEFT_ITEM); >- } >- break; >- case KEY_LEFT: >- menu_driver(menu, REQ_LEFT_ITEM); >- break; >- case '\t': >- if (current_item_is_last(menu)) { >- menu_driver(menu, REQ_FIRST_ITEM); >- break; >+ c = regedit_getch(); >+ if (c == KEY_RESIZE) { >+ int nlines, ncols, y, x; >+ >+ getmaxyx(dia->window, nlines, ncols); >+ getbegyx(dia->window, y, x); >+ if (dia->centered) { >+ center_above_window(&nlines, &ncols, &y, &x); > } else { >- menu_driver(menu, REQ_RIGHT_ITEM); >+ if (nlines + y > LINES) { >+ if (nlines > LINES) { >+ y = 0; >+ } else { >+ y = LINES - nlines; >+ } >+ } >+ if (ncols + x > COLS) { >+ if (ncols > COLS) { >+ x = 0; >+ } else { >+ x = COLS - ncols; >+ } >+ } > } >- case KEY_RIGHT: >- menu_driver(menu, REQ_RIGHT_ITEM); >- break; >- case KEY_ENTER: >- case '\n': >- item = current_item(menu); >- return (int)(uintptr_t)item_userptr(item); >+ move_panel(dia->panel, y, x); > } > >- return -1; >+ return c; > } > >-static void handle_form_input(FORM *frm, int c) >+bool dialog_handle_input(struct dialog *dia, WERROR *err, >+ enum dialog_action *action) > { >+ int c; >+ >+ *err = WERR_OK; >+ >+ c = dialog_getch(dia); >+ > switch (c) { >- case '\n': >- form_driver(frm, REQ_NEW_LINE); >+ case '\t': >+ if (!section_on_tab(dia)) { >+ section_set_next_focus(dia); >+ } >+ break; >+ case KEY_BTAB: >+ if (!section_on_btab(dia)) { >+ section_set_previous_focus(dia); >+ } > break; > case KEY_UP: >- form_driver(frm, REQ_UP_CHAR); >+ if (!section_on_up(dia)) { >+ section_set_previous_focus(dia); >+ } > break; > case KEY_DOWN: >- form_driver(frm, REQ_DOWN_CHAR); >- break; >- case '\b': >- case KEY_BACKSPACE: >- form_driver(frm, REQ_DEL_PREV); >+ if (!section_on_down(dia)) { >+ section_set_next_focus(dia); >+ } > break; > case KEY_LEFT: >- form_driver(frm, REQ_LEFT_CHAR); >+ if (!section_on_left(dia)) { >+ section_set_previous_focus(dia); >+ } > break; > case KEY_RIGHT: >- form_driver(frm, REQ_RIGHT_CHAR); >+ if (!section_on_right(dia)) { >+ section_set_next_focus(dia); >+ } >+ break; >+ case '\n': >+ case KEY_ENTER: >+ *action = section_on_enter(dia); >+ switch (*action) { >+ case DIALOG_IGNORE: >+ break; >+ case DIALOG_CANCEL: >+ return false; >+ case DIALOG_OK: >+ return !dia->submit(dia, dia->current_section, >+ dia->submit_arg); >+ } > break; >+ case 27: /* ESC */ >+ return false; > default: >- form_driver(frm, c); >+ section_on_input(dia, c); > break; > } >+ >+ return true; > } > >-static int modal_loop(struct dialog *dia) >+void dialog_modal_loop(struct dialog *dia, WERROR *err, >+ enum dialog_action *action) > { >- int c; >- int selection = -1; >- >- update_panels(); >- doupdate(); >- >- while (selection == -1) { >- c = dialog_getch(dia); >- selection = handle_menu_input(dia->choices, c); >+ do { > update_panels(); > doupdate(); >+ } while (dialog_handle_input(dia, err, action)); >+} >+ >+/* text label */ >+struct dialog_section_label { >+ struct dialog_section section; >+ char **text; >+}; >+ >+static WERROR label_create(struct dialog *dia, struct dialog_section *section) >+{ >+ int row; >+ struct dialog_section_label *label = >+ talloc_get_type_abort(section, struct dialog_section_label); >+ >+ for (row = 0; row < section->nlines; ++row) { >+ mvwaddstr(section->window, row, 0, label->text[row]); > } > >- talloc_free(dia); >+ return WERR_OK; >+} >+ >+struct dialog_section_ops label_ops = { >+ .create = label_create, >+}; >+ >+static int label_free(struct dialog_section_label *label) >+{ >+ dialog_section_destroy(&label->section); >+ return 0; >+} >+ >+struct dialog_section *dialog_section_label_new_va(TALLOC_CTX *ctx, >+ const char *msg, va_list ap) >+{ >+ struct dialog_section_label *label; >+ char *tmp, *ptmp, *line, *saveptr; >+ int nlines, ncols; >+ >+ label = talloc_zero(ctx, struct dialog_section_label); >+ if (label == NULL) { >+ return NULL; >+ } >+ talloc_set_destructor(label, label_free); >+ tmp = talloc_vasprintf(label, msg, ap); >+ if (tmp == NULL) { >+ goto fail; >+ } >+ >+ for (nlines = 0, ncols = 0, ptmp = tmp; >+ (line = strtok_r(ptmp, "\n", &saveptr)) != NULL; >+ ++nlines) { >+ ptmp = NULL; >+ label->text = talloc_realloc(label, label->text, >+ char *, nlines + 1); >+ if (label->text == NULL) { >+ goto fail; >+ } >+ ncols = MAX(ncols, strlen(line)); >+ label->text[nlines] = talloc_strdup(label->text, line); >+ if (label->text[nlines] == NULL) { >+ goto fail; >+ } >+ } >+ talloc_free(tmp); >+ dialog_section_init(&label->section, &label_ops, nlines, ncols); >+ >+ return &label->section; >+ >+fail: >+ talloc_free(label); >+ return NULL; >+} >+ >+struct dialog_section *dialog_section_label_new(TALLOC_CTX *ctx, >+ const char *msg, ...) >+{ >+ va_list ap; >+ struct dialog_section *rv; >+ >+ va_start(ap, msg); >+ rv = dialog_section_label_new_va(ctx, msg, ap); >+ va_end(ap); >+ >+ return rv; >+} >+ >+/* horizontal separator */ >+struct dialog_section_hsep { >+ struct dialog_section section; >+ int sep; >+}; >+ >+static WERROR hsep_create(struct dialog *dia, struct dialog_section *section) >+{ >+ int y, x; >+ struct dialog_section_hsep *hsep = >+ talloc_get_type_abort(section, struct dialog_section_hsep); >+ >+ whline(section->window, hsep->sep, section->ncols); >+ >+ if (hsep->sep == 0 || hsep->sep == ACS_HLINE) { >+ /* change the border characters around this section to >+ tee chars */ >+ getparyx(section->window, y, x); >+ mvwaddch(dia->window, y, x - 1, ACS_HLINE); >+ mvwaddch(dia->window, y, x - 2, ACS_LTEE); >+ mvwaddch(dia->window, y, x + section->ncols, ACS_HLINE); >+ mvwaddch(dia->window, y, x + section->ncols + 1, ACS_RTEE); >+ } >+ >+ return WERR_OK; >+} >+ >+struct dialog_section_ops hsep_ops = { >+ .create = hsep_create >+}; >+ >+static int hsep_free(struct dialog_section_hsep *hsep) >+{ >+ dialog_section_destroy(&hsep->section); >+ return 0; >+} >+ >+struct dialog_section *dialog_section_hsep_new(TALLOC_CTX *ctx, int sep) >+{ >+ struct dialog_section_hsep *hsep; >+ >+ hsep = talloc_zero(ctx, struct dialog_section_hsep); >+ if (hsep) { >+ talloc_set_destructor(hsep, hsep_free); >+ dialog_section_init(&hsep->section, &hsep_ops, 1, -1); >+ hsep->sep = sep; >+ } >+ >+ return &hsep->section; >+} >+ >+/* text input field */ >+struct dialog_section_text_field { >+ struct dialog_section section; >+ unsigned opts; >+ FIELD *field[2]; >+ FORM *form; >+}; >+ >+static WERROR text_field_create(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ text_field->field[0] = new_field(section->nlines, section->ncols, >+ 0, 0, 0, 0); >+ if (text_field->field[0] == NULL) { >+ return WERR_NOMEM; >+ } >+ set_field_back(text_field->field[0], A_REVERSE); >+ set_field_opts(text_field->field[0], text_field->opts); >+ >+ text_field->form = new_form(text_field->field); >+ if (text_field->form == NULL) { >+ return WERR_NOMEM; >+ } >+ >+ set_form_win(text_field->form, dia->window); >+ set_form_sub(text_field->form, section->window); >+ set_current_field(text_field->form, text_field->field[0]); >+ post_form(text_field->form); >+ >+ return WERR_OK; >+} >+ >+static void text_field_destroy(struct dialog_section *section) >+{ >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ if (text_field->form) { >+ unpost_form(text_field->form); >+ free_form(text_field->form); >+ text_field->form = NULL; >+ } >+ if (text_field->field[0]) { >+ free_field(text_field->field[0]); >+ text_field->field[0] = NULL; >+ } >+} >+ >+static void text_field_on_input(struct dialog *dia, >+ struct dialog_section *section, >+ int c) >+{ >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ switch (c) { >+ case KEY_BACKSPACE: >+ form_driver(text_field->form, REQ_DEL_PREV); >+ break; >+ default: >+ form_driver(text_field->form, c); >+ break; >+ } >+} >+ >+static bool text_field_on_up(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ if (section->nlines > 1) { >+ form_driver(text_field->form, REQ_UP_CHAR); >+ return true; >+ } >+ return false; >+} >+ >+static bool text_field_on_down(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ if (section->nlines > 1) { >+ form_driver(text_field->form, REQ_DOWN_CHAR); >+ return true; >+ } >+ return false; >+} >+ >+static bool text_field_on_left(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ form_driver(text_field->form, REQ_LEFT_CHAR); >+ >+ return true; >+} >+ >+static bool text_field_on_right(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ form_driver(text_field->form, REQ_RIGHT_CHAR); >+ >+ return true; >+} >+ >+static enum dialog_action text_field_on_enter(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ if (section->nlines > 1) { >+ form_driver(text_field->form, REQ_NEW_LINE); >+ return DIALOG_IGNORE; >+ } >+ >+ return DIALOG_OK; >+} >+ >+static bool text_field_on_focus(struct dialog *dia, >+ struct dialog_section *section, bool forward) >+{ >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ pos_form_cursor(text_field->form); >+ >+ return true; >+} >+ >+struct dialog_section_ops text_field_ops = { >+ .create = text_field_create, >+ .destroy = text_field_destroy, >+ .on_input = text_field_on_input, >+ .on_up = text_field_on_up, >+ .on_down = text_field_on_down, >+ .on_left = text_field_on_left, >+ .on_right = text_field_on_right, >+ .on_enter = text_field_on_enter, >+ .on_focus = text_field_on_focus >+}; >+ >+static int text_field_free(struct dialog_section_text_field *text_field) >+{ >+ dialog_section_destroy(&text_field->section); >+ return 0; >+} >+ >+struct dialog_section *dialog_section_text_field_new(TALLOC_CTX *ctx, >+ int height, int width) >+{ >+ struct dialog_section_text_field *text_field; >+ >+ text_field = talloc_zero(ctx, struct dialog_section_text_field); >+ if (text_field == NULL) { >+ return NULL; >+ } >+ talloc_set_destructor(text_field, text_field_free); >+ dialog_section_init(&text_field->section, &text_field_ops, >+ height, width); >+ text_field->opts = O_ACTIVE | O_PUBLIC | O_EDIT | O_VISIBLE | O_NULLOK; >+ >+ return &text_field->section; >+} >+ >+const char *dialog_section_text_field_get(TALLOC_CTX *ctx, >+ struct dialog_section *section) >+{ >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ form_driver(text_field->form, REQ_VALIDATION); >+ >+ return string_trim(ctx, field_buffer(text_field->field[0], 0)); >+} >+ >+void dialog_section_text_field_set(struct dialog_section *section, >+ const char *s) >+{ >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ set_field_buffer(text_field->field[0], 0, s); >+} >+ >+const char **dialog_section_text_field_get_lines(TALLOC_CTX *ctx, >+ struct dialog_section *section) >+{ >+ int rows, cols, max; >+ const char **arr; >+ size_t i; >+ const char *buf; >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ form_driver(text_field->form, REQ_VALIDATION); >+ buf = field_buffer(text_field->field[0], 0); >+ >+ dynamic_field_info(text_field->field[0], &rows, &cols, &max); >+ >+ arr = talloc_zero_array(ctx, const char *, rows + 1); >+ if (arr == NULL) { >+ return NULL; >+ } >+ for (i = 0; *buf; ++i, buf += cols) { >+ SMB_ASSERT(i < rows); >+ arr[i] = string_trim_n(arr, buf, cols); >+ } >+ >+ return arr; >+} >+ >+WERROR dialog_section_text_field_set_lines(TALLOC_CTX *ctx, >+ struct dialog_section *section, >+ const char **array) >+{ >+ int rows, cols, max; >+ size_t padding, length, index; >+ const char **arrayp; >+ char *buf = NULL; >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ dynamic_field_info(text_field->field[0], &rows, &cols, &max); >+ /* try to fit each string on it's own line. each line >+ needs to be padded with whitespace manually, since >+ ncurses fields do not have newlines. */ >+ for (index = 0, arrayp = array; *arrayp != NULL; ++arrayp) { >+ length = MIN(strlen(*arrayp), cols); >+ padding = cols - length; >+ buf = talloc_realloc(ctx, buf, char, >+ talloc_array_length(buf) + >+ length + padding + 1); >+ if (buf == NULL) { >+ return WERR_NOMEM; >+ } >+ memcpy(&buf[index], *arrayp, length); >+ index += length; >+ memset(&buf[index], ' ', padding); >+ index += padding; >+ buf[index] = '\0'; >+ } >+ >+ set_field_buffer(text_field->field[0], 0, buf); >+ talloc_free(buf); >+ >+ return WERR_OK; >+} >+ >+bool dialog_section_text_field_get_int(struct dialog_section *section, >+ long long *out) >+{ >+ bool rv; >+ const char *buf; >+ char *endp; >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ form_driver(text_field->form, REQ_VALIDATION); >+ >+ buf = string_trim(section, field_buffer(text_field->field[0], 0)); >+ if (buf == NULL) { >+ return false; >+ } >+ *out = strtoll(buf, &endp, 0); >+ rv = true; >+ if (endp == buf || endp == NULL || endp[0] != '\0') { >+ rv = false; >+ } >+ >+ return rv; >+} >+ >+ >+bool dialog_section_text_field_get_uint(struct dialog_section *section, >+ unsigned long long *out) >+{ >+ bool rv; >+ const char *buf; >+ char *endp; >+ struct dialog_section_text_field *text_field = >+ talloc_get_type_abort(section, struct dialog_section_text_field); >+ >+ form_driver(text_field->form, REQ_VALIDATION); >+ >+ buf = string_trim(section, field_buffer(text_field->field[0], 0)); >+ if (buf == NULL) { >+ return false; >+ } >+ *out = strtoull(buf, &endp, 0); >+ rv = true; >+ if (endp == buf || endp == NULL || endp[0] != '\0') { >+ rv = false; >+ } >+ >+ return rv; >+} >+ >+/* hex editor field */ >+struct dialog_section_hexedit { >+ struct dialog_section section; >+ struct hexedit *buf; >+}; >+ >+#define HEXEDIT_MIN_SIZE 16 >+static WERROR hexedit_create(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_hexedit *hexedit = >+ talloc_get_type_abort(section, struct dialog_section_hexedit); >+ >+ hexedit->buf = hexedit_new(dia, section->window, section->nlines, >+ 0, 0, NULL, HEXEDIT_MIN_SIZE); >+ if (hexedit->buf == NULL) { >+ return WERR_NOMEM; >+ } >+ >+ hexedit_refresh(hexedit->buf); >+ >+ return WERR_OK; >+} >+ >+static void hexedit_destroy(struct dialog_section *section) >+{ >+ struct dialog_section_hexedit *hexedit = >+ talloc_get_type_abort(section, struct dialog_section_hexedit); >+ >+ if (hexedit->buf) { >+ TALLOC_FREE(hexedit->buf); >+ } >+} >+ >+static void hexedit_on_input(struct dialog *dia, >+ struct dialog_section *section, >+ int c) >+{ >+ struct dialog_section_hexedit *hexedit = >+ talloc_get_type_abort(section, struct dialog_section_hexedit); >+ >+ switch (c) { >+ case KEY_BACKSPACE: >+ // FIXME hexedit_driver(hexedit->buf, c); >+ break; >+ default: >+ hexedit_driver(hexedit->buf, c); >+ break; >+ } >+} >+ >+static bool hexedit_on_up(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_hexedit *hexedit = >+ talloc_get_type_abort(section, struct dialog_section_hexedit); >+ >+ hexedit_driver(hexedit->buf, HE_CURSOR_UP); >+ >+ return true; >+} >+ >+static bool hexedit_on_down(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_hexedit *hexedit = >+ talloc_get_type_abort(section, struct dialog_section_hexedit); >+ >+ hexedit_driver(hexedit->buf, HE_CURSOR_DOWN); >+ >+ return true; >+} >+ >+static bool hexedit_on_left(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_hexedit *hexedit = >+ talloc_get_type_abort(section, struct dialog_section_hexedit); >+ >+ hexedit_driver(hexedit->buf, HE_CURSOR_LEFT); >+ >+ return true; >+} >+ >+static bool hexedit_on_right(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_hexedit *hexedit = >+ talloc_get_type_abort(section, struct dialog_section_hexedit); >+ >+ hexedit_driver(hexedit->buf, HE_CURSOR_RIGHT); >+ >+ return true; >+} >+ >+static enum dialog_action hexedit_on_enter(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ return DIALOG_IGNORE; >+} >+ >+static bool hexedit_on_focus(struct dialog *dia, >+ struct dialog_section *section, bool forward) >+{ >+ struct dialog_section_hexedit *hexedit = >+ talloc_get_type_abort(section, struct dialog_section_hexedit); >+ >+ hexedit_set_cursor(hexedit->buf); >+ >+ return true; >+} >+ >+struct dialog_section_ops hexedit_ops = { >+ .create = hexedit_create, >+ .destroy = hexedit_destroy, >+ .on_input = hexedit_on_input, >+ .on_up = hexedit_on_up, >+ .on_down = hexedit_on_down, >+ .on_left = hexedit_on_left, >+ .on_right = hexedit_on_right, >+ .on_enter = hexedit_on_enter, >+ .on_focus = hexedit_on_focus >+}; >+ >+static int hexedit_free(struct dialog_section_hexedit *hexedit) >+{ >+ dialog_section_destroy(&hexedit->section); >+ return 0; >+} >+ >+struct dialog_section *dialog_section_hexedit_new(TALLOC_CTX *ctx, int height) >+{ >+ struct dialog_section_hexedit *hexedit; >+ >+ hexedit = talloc_zero(ctx, struct dialog_section_hexedit); >+ if (hexedit == NULL) { >+ return NULL; >+ } >+ talloc_set_destructor(hexedit, hexedit_free); >+ dialog_section_init(&hexedit->section, &hexedit_ops, >+ height, LINE_WIDTH); >+ >+ return &hexedit->section; >+} >+ >+WERROR dialog_section_hexedit_set_buf(struct dialog_section *section, >+ const void *data, size_t size) >+{ >+ WERROR rv; >+ struct dialog_section_hexedit *hexedit = >+ talloc_get_type_abort(section, struct dialog_section_hexedit); >+ >+ SMB_ASSERT(hexedit->buf != NULL); >+ >+ rv = hexedit_set_buf(hexedit->buf, data, size); >+ if (W_ERROR_IS_OK(rv)) { >+ hexedit_refresh(hexedit->buf); >+ hexedit_set_cursor(hexedit->buf); >+ } >+ >+ return rv; >+} >+ >+void dialog_section_hexedit_get_buf(struct dialog_section *section, >+ const void **data, size_t *size) >+{ >+ struct dialog_section_hexedit *hexedit = >+ talloc_get_type_abort(section, struct dialog_section_hexedit); >+ >+ SMB_ASSERT(hexedit->buf != NULL); >+ *data = hexedit_get_buf(hexedit->buf); >+ *size = hexedit_get_buf_len(hexedit->buf); >+} >+ >+/* button box */ >+struct dialog_section_buttons { >+ struct dialog_section section; >+ struct button_spec *spec; >+ int current_button; >+}; >+ >+static void buttons_unhighlight(struct dialog_section_buttons *buttons) >+{ >+ short pair; >+ attr_t attr; >+ >+ /* >+ * Some GCC versions will complain if the macro version of >+ * wattr_get is used. So we should enforce the use of the >+ * function instead. See: >+ * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html >+ */ >+ (wattr_get)(buttons->section.window, &attr, &pair, NULL); >+ mvwchgat(buttons->section.window, 0, 0, -1, A_NORMAL, pair, NULL); >+ wnoutrefresh(buttons->section.window); >+} >+ >+static void buttons_highlight(struct dialog_section_buttons *buttons) >+{ >+ struct button_spec *button = &buttons->spec[buttons->current_button]; >+ short pair; >+ attr_t attr; >+ >+ /* >+ * Some GCC versions will complain if the macro version of >+ * wattr_get is used. So we should enforce the use of the >+ * function instead. See: >+ * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html >+ */ >+ (wattr_get)(buttons->section.window, &attr, &pair, NULL); >+ mvwchgat(buttons->section.window, 0, 0, -1, A_NORMAL, pair, NULL); >+ mvwchgat(buttons->section.window, 0, button->col, >+ strlen(button->label), A_REVERSE, pair, NULL); >+ wmove(buttons->section.window, 0, button->col + 2); >+ wcursyncup(buttons->section.window); >+ wnoutrefresh(buttons->section.window); >+} >+ >+static bool buttons_highlight_next(struct dialog_section_buttons *buttons) >+{ >+ if (buttons->current_button < talloc_array_length(buttons->spec) - 1) { >+ buttons->current_button++; >+ buttons_highlight(buttons); >+ return true; >+ } >+ return false; >+} >+ >+static bool buttons_highlight_previous(struct dialog_section_buttons *buttons) >+{ >+ if (buttons->current_button > 0) { >+ buttons->current_button--; >+ buttons_highlight(buttons); >+ return true; >+ } >+ return false; >+} >+ >+static WERROR buttons_create(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ size_t i, nbuttons; >+ struct dialog_section_buttons *buttons = >+ talloc_get_type_abort(section, struct dialog_section_buttons); >+ >+ nbuttons = talloc_array_length(buttons->spec); >+ for (i = 0; i < nbuttons; ++i) { >+ struct button_spec *button = &buttons->spec[i]; >+ mvwaddstr(section->window, 0, button->col, button->label); >+ } >+ >+ buttons->current_button = 0; >+ >+ return WERR_OK; >+} >+ >+static bool buttons_on_btab(struct dialog *dia, struct dialog_section *section) >+{ >+ struct dialog_section_buttons *buttons = >+ talloc_get_type_abort(section, struct dialog_section_buttons); >+ >+ return buttons_highlight_previous(buttons); >+} >+ >+static bool buttons_on_tab(struct dialog *dia, struct dialog_section *section) >+{ >+ struct dialog_section_buttons *buttons = >+ talloc_get_type_abort(section, struct dialog_section_buttons); >+ >+ return buttons_highlight_next(buttons); >+} >+ >+static enum dialog_action buttons_on_enter(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_buttons *buttons = >+ talloc_get_type_abort(section, struct dialog_section_buttons); >+ struct button_spec *spec = &buttons->spec[buttons->current_button]; >+ >+ if (spec->on_enter) { >+ return spec->on_enter(dia, section); >+ } >+ >+ return spec->action; >+} >+ >+static bool buttons_on_focus(struct dialog *dia, >+ struct dialog_section *section, >+ bool forward) >+{ >+ struct dialog_section_buttons *buttons = >+ talloc_get_type_abort(section, struct dialog_section_buttons); >+ >+ if (forward) { >+ buttons->current_button = 0; >+ } else { >+ buttons->current_button = talloc_array_length(buttons->spec) - 1; >+ } >+ buttons_highlight(buttons); >+ >+ return true; >+} >+ >+static void buttons_on_leave_focus(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_buttons *buttons = >+ talloc_get_type_abort(section, struct dialog_section_buttons); >+ buttons_unhighlight(buttons); >+} >+ >+struct dialog_section_ops buttons_ops = { >+ .create = buttons_create, >+ .on_tab = buttons_on_tab, >+ .on_btab = buttons_on_btab, >+ .on_up = buttons_on_btab, >+ .on_down = buttons_on_tab, >+ .on_left = buttons_on_btab, >+ .on_right = buttons_on_tab, >+ .on_enter = buttons_on_enter, >+ .on_focus = buttons_on_focus, >+ .on_leave_focus = buttons_on_leave_focus >+}; >+ >+static int buttons_free(struct dialog_section_buttons *buttons) >+{ >+ dialog_section_destroy(&buttons->section); >+ return 0; >+} >+ >+struct dialog_section *dialog_section_buttons_new(TALLOC_CTX *ctx, >+ const struct button_spec *spec) >+{ >+ struct dialog_section_buttons *buttons; >+ size_t i, nbuttons; >+ int width; >+ >+ buttons = talloc_zero(ctx, struct dialog_section_buttons); >+ if (buttons == NULL) { >+ return NULL; >+ } >+ talloc_set_destructor(buttons, buttons_free); >+ >+ for (nbuttons = 0; spec[nbuttons].label; ++nbuttons) { >+ } >+ buttons->spec = talloc_zero_array(buttons, struct button_spec, nbuttons); >+ if (buttons->spec == NULL) { >+ goto fail; >+ } >+ >+ for (width = 0, i = 0; i < nbuttons; ++i) { >+ buttons->spec[i] = spec[i]; >+ buttons->spec[i].label = talloc_asprintf(buttons->spec, >+ "[ %s ]", >+ spec[i].label); >+ if (!buttons->spec[i].label) { >+ goto fail; >+ } >+ >+ buttons->spec[i].col = width; >+ width += strlen(buttons->spec[i].label); >+ if (i != nbuttons - 1) { >+ ++width; >+ } >+ } >+ >+ dialog_section_init(&buttons->section, &buttons_ops, 1, width); >+ >+ return &buttons->section; >+ >+fail: >+ talloc_free(buttons); >+ return NULL; >+} >+ >+/* options */ >+struct dialog_section_options { >+ struct dialog_section section; >+ struct option_spec *spec; >+ int current_option; >+ bool single_select; >+}; >+ >+static void options_unhighlight(struct dialog_section_options *options) >+{ >+ short pair; >+ attr_t attr; >+ size_t row; >+ >+ /* >+ * Some GCC versions will complain if the macro version of >+ * wattr_get is used. So we should enforce the use of the >+ * function instead. See: >+ * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html >+ */ >+ (wattr_get)(options->section.window, &attr, &pair, NULL); >+ for (row = 0; row < options->section.nlines; ++row) { >+ mvwchgat(options->section.window, row, 0, -1, A_NORMAL, pair, NULL); >+ } >+ wnoutrefresh(options->section.window); >+} >+ >+static void options_highlight(struct dialog_section_options *options) >+{ >+ struct option_spec *option = &options->spec[options->current_option]; >+ short pair; >+ attr_t attr; >+ size_t row; >+ >+ /* >+ * Some GCC versions will complain if the macro version of >+ * wattr_get is used. So we should enforce the use of the >+ * function instead. See: >+ * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html >+ */ >+ (wattr_get)(options->section.window, &attr, &pair, NULL); >+ for (row = 0; row < options->section.nlines; ++row) { >+ mvwchgat(options->section.window, row, 0, -1, A_NORMAL, pair, NULL); >+ } >+ mvwchgat(options->section.window, option->row, option->col, >+ strlen(option->label), A_REVERSE, pair, NULL); >+ wmove(options->section.window, option->row, option->col + 4); >+ wcursyncup(options->section.window); >+ wnoutrefresh(options->section.window); >+} >+ >+static void options_render_state(struct dialog_section_options *options) >+{ >+ size_t i, noptions; >+ >+ noptions = talloc_array_length(options->spec); >+ for (i = 0; i < noptions; ++i) { >+ struct option_spec *option = &options->spec[i]; >+ char c = ' '; >+ if (*option->state) >+ c = 'x'; >+ mvwaddch(options->section.window, >+ option->row, option->col + 1, c); >+ wnoutrefresh(options->section.window); >+ } >+} >+ >+static bool options_highlight_next(struct dialog_section_options *options) >+{ >+ if (options->current_option < talloc_array_length(options->spec) - 1) { >+ options->current_option++; >+ options_highlight(options); >+ return true; >+ } >+ return false; >+} >+ >+static bool options_highlight_previous(struct dialog_section_options *options) >+{ >+ if (options->current_option > 0) { >+ options->current_option--; >+ options_highlight(options); >+ return true; >+ } >+ return false; >+} >+ >+static WERROR options_create(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ size_t i, noptions; >+ struct dialog_section_options *options = >+ talloc_get_type_abort(section, struct dialog_section_options); >+ >+ noptions = talloc_array_length(options->spec); >+ for (i = 0; i < noptions; ++i) { >+ struct option_spec *option = &options->spec[i]; >+ mvwaddstr(section->window, option->row, option->col, >+ option->label); >+ } >+ >+ options->current_option = 0; >+ options_render_state(options); >+ >+ return WERR_OK; >+} >+ >+static bool options_on_btab(struct dialog *dia, struct dialog_section *section) >+{ >+ struct dialog_section_options *options = >+ talloc_get_type_abort(section, struct dialog_section_options); >+ >+ return options_highlight_previous(options); >+} >+ >+static bool options_on_tab(struct dialog *dia, struct dialog_section *section) >+{ >+ struct dialog_section_options *options = >+ talloc_get_type_abort(section, struct dialog_section_options); >+ >+ return options_highlight_next(options); >+} >+ >+static void options_on_input(struct dialog *dia, struct dialog_section *section, int c) >+{ >+ struct dialog_section_options *options = >+ talloc_get_type_abort(section, struct dialog_section_options); >+ >+ if (c == ' ') { >+ struct option_spec *option = &options->spec[options->current_option]; >+ if (options->single_select) { >+ size_t i, noptions; >+ noptions = talloc_array_length(options->spec); >+ for (i = 0; i < noptions; ++i) { >+ *(options->spec[i].state) = false; >+ } >+ } >+ *option->state = !*option->state; >+ options_unhighlight(options); >+ options_render_state(options); >+ options_highlight(options); >+ } >+} >+ >+static enum dialog_action options_on_enter(struct dialog *dia, struct dialog_section *section) >+{ >+ options_on_input(dia, section, ' '); >+ return DIALOG_OK; >+} >+ >+static bool options_on_focus(struct dialog *dia, >+ struct dialog_section *section, >+ bool forward) >+{ >+ struct dialog_section_options *options = >+ talloc_get_type_abort(section, struct dialog_section_options); >+ >+ if (forward) { >+ options->current_option = 0; >+ } else { >+ options->current_option = talloc_array_length(options->spec) - 1; >+ } >+ options_highlight(options); >+ >+ return true; >+} >+ >+static void options_on_leave_focus(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section_options *options = >+ talloc_get_type_abort(section, struct dialog_section_options); >+ options_unhighlight(options); >+} >+ >+struct dialog_section_ops options_ops = { >+ .create = options_create, >+ .on_tab = options_on_tab, >+ .on_btab = options_on_btab, >+ .on_up = options_on_btab, >+ .on_down = options_on_tab, >+ .on_left = options_on_btab, >+ .on_right = options_on_tab, >+ .on_input = options_on_input, >+ .on_enter = options_on_enter, >+ .on_focus = options_on_focus, >+ .on_leave_focus = options_on_leave_focus >+}; > >- return selection; >+static int options_free(struct dialog_section_options *options) >+{ >+ dialog_section_destroy(&options->section); >+ return 0; > } > >-static struct dialog *dialog_msg_new(TALLOC_CTX *ctx, const char *title, >- const char **choices, int nlines, >- const char *msg, va_list ap) >+struct dialog_section *dialog_section_options_new(TALLOC_CTX *ctx, >+ const struct option_spec *spec, >+ int maxcol, bool single_select) > { >- struct dialog *dia; >- char *str; >- int width; >-#define MIN_WIDTH 20 >+ struct dialog_section_options *options; >+ size_t i, noptions; >+ int width, maxwidth, maxrows; > >- str = talloc_vasprintf(ctx, msg, ap); >- if (str == NULL) { >+ options = talloc_zero(ctx, struct dialog_section_options); >+ if (options == NULL) { > return NULL; > } >+ talloc_set_destructor(options, options_free); > >- width = strlen(str) + 2; >- if (width < MIN_WIDTH) { >- width = MIN_WIDTH; >+ for (noptions = 0; spec[noptions].label; ++noptions) { > } >- dia = dialog_choice_center_new(ctx, title, choices, nlines, width); >- if (dia == NULL) { >- return NULL; >+ options->spec = talloc_zero_array(options, struct option_spec, noptions); >+ if (options->spec == NULL) { >+ goto fail; > } > >- waddstr(dia->sub_window, str); >- talloc_free(str); >+ maxrows = noptions / maxcol; >+ if (noptions % maxcol) { >+ ++maxrows; >+ } > >- return dia; >+ for (width = 0, maxwidth = 0, i = 0; i < noptions; ++i) { >+ options->spec[i] = spec[i]; >+ options->spec[i].label = talloc_asprintf(options->spec, >+ "[ ] %s", >+ spec[i].label); >+ if (!options->spec[i].label) { >+ goto fail; >+ } >+ >+ options->spec[i].col = maxwidth; >+ options->spec[i].row = i % maxrows; >+ width = MAX(strlen(options->spec[i].label), width); >+ if (options->spec[i].row == maxrows - 1 || i == noptions - 1) { >+ maxwidth += width + 1; >+ width = 0; >+ } >+ } >+ >+ dialog_section_init(&options->section, &options_ops, maxrows, maxwidth - 1); >+ options->single_select = single_select; >+ >+ return &options->section; >+ >+fail: >+ talloc_free(options); >+ return NULL; > } > >-int dialog_input(TALLOC_CTX *ctx, char **output, const char *title, >+ >+int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title, > const char *msg, ...) > { > va_list ap; >+ WERROR err; >+ enum dialog_action action; > struct dialog *dia; >- const char *choices[] = { >- "Ok", >- "Cancel", >- NULL >+ struct dialog_section *section; >+ struct button_spec spec[] = { >+ {.label = "OK", .action = DIALOG_OK}, >+ {.label = "Cancel", .action = DIALOG_CANCEL}, >+ { 0 } > }; >- FIELD *field[2] = {0}; >- FORM *input; >- WINDOW *input_win; >- int y, x; >- int rv = -1; >- bool input_section = true; > >+ dia = dialog_new(ctx, PAIR_BLACK_CYAN, title, -1, -1); > va_start(ap, msg); >- dia = dialog_msg_new(ctx, title, choices, 7, msg, ap); >+ section = dialog_section_label_new_va(dia, msg, ap); > va_end(ap); >- if (dia == NULL) { >- return -1; >- } >- >- getmaxyx(dia->sub_window, y, x); >- input_win = derwin(dia->sub_window, 1, x - 2, 2, 1); >- if (input_win == NULL) { >- goto finish; >- } >- field[0] = new_field(1, x - 2, 0, 0, 0, 0); >- if (field[0] == NULL) { >- goto finish; >- } >+ dialog_append_section(dia, section); >+ section = dialog_section_hsep_new(dia, ' '); >+ dialog_append_section(dia, section); >+ section = dialog_section_text_field_new(dia, 1, -1); >+ dialog_section_set_name(section, "input"); >+ dialog_append_section(dia, section); >+ section = dialog_section_hsep_new(dia, 0); >+ dialog_append_section(dia, section); >+ section = dialog_section_buttons_new(dia, spec); >+ dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER); >+ dialog_append_section(dia, section); >+ >+ dialog_create(dia); >+ dialog_show(dia); >+ dialog_modal_loop(dia, &err, &action); > >- field_opts_off(field[0], O_BLANK | O_AUTOSKIP | O_STATIC); >- set_field_back(field[0], A_REVERSE); >- >- input = new_form(field); >- form_opts_off(input, O_NL_OVERLOAD | O_BS_OVERLOAD); >- set_form_win(input, dia->sub_window); >- set_form_sub(input, input_win); >- set_current_field(input, field[0]); >- post_form(input); > *output = NULL; >- >- update_panels(); >- doupdate(); >- >- while (rv == -1) { >- int c = dialog_getch(dia); >- >- if (c == '\t' || c == KEY_BTAB) { >- if (input_section) { >- int valid = form_driver(input, REQ_VALIDATION); >- if (valid == E_OK) { >- input_section = false; >- if (c == '\t') { >- menu_driver(dia->choices, >- REQ_FIRST_ITEM); >- } else { >- menu_driver(dia->choices, >- REQ_LAST_ITEM); >- } >- pos_menu_cursor(dia->choices); >- } >- } else { >- if ((c == '\t' && >- current_item_is_last(dia->choices)) || >- (c == KEY_BTAB && >- current_item_is_first(dia->choices))) { >- input_section = true; >- set_current_field(input, field[0]); >- pos_form_cursor(input); >- } else { >- handle_menu_input(dia->choices, c); >- } >- } >- } else if (input_section) { >- handle_form_input(input, c); >- } else { >- rv = handle_menu_input(dia->choices, c); >- if (rv == DIALOG_OK) { >- const char *buf = field_buffer(field[0], 0); >- *output = string_trim(ctx, buf); >- } >- } >- update_panels(); >- doupdate(); >+ if (action == DIALOG_OK) { >+ section = dialog_find_section(dia, "input"); >+ *output = dialog_section_text_field_get(ctx, section); > } > >-finish: >- if (input) { >- unpost_form(input); >- free_form(input); >- } >- if (field[0]) { >- free_field(field[0]); >- } >- if (input_win) { >- delwin(input_win); >- } > talloc_free(dia); > >- return rv; >+ return action; > } > > int dialog_notice(TALLOC_CTX *ctx, enum dialog_type type, > const char *title, const char *msg, ...) > { > va_list ap; >+ WERROR err; >+ enum dialog_action action; > struct dialog *dia; >- const char *choices[] = { >- "Ok", >- "Cancel", >- NULL >- }; >+ struct dialog_section *section; >+ struct button_spec spec[3]; > >- if (type == DIA_ALERT) { >- choices[1] = NULL; >+ memset(&spec, '\0', sizeof(spec)); >+ spec[0].label = "OK"; >+ spec[0].action = DIALOG_OK; >+ if (type == DIA_CONFIRM) { >+ spec[1].label = "Cancel"; >+ spec[1].action = DIALOG_CANCEL; > } > >+ dia = dialog_new(ctx, PAIR_BLACK_CYAN, title, -1, -1); > va_start(ap, msg); >- dia = dialog_msg_new(ctx, title, choices, 5, msg, ap); >+ section = dialog_section_label_new_va(dia, msg, ap); > va_end(ap); >- if (dia == NULL) { >- return -1; >- } >+ dialog_append_section(dia, section); >+ section = dialog_section_hsep_new(dia, 0); >+ dialog_append_section(dia, section); >+ section = dialog_section_buttons_new(dia, spec); >+ dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER); >+ dialog_append_section(dia, section); >+ >+ dialog_create(dia); >+ dialog_show(dia); >+ dialog_modal_loop(dia, &err, &action); >+ talloc_free(dia); > >- return modal_loop(dia); >+ return action; > } > >-#define EDIT_WIDTH 50 >-#define EDIT_INTERNAL_WIDTH (EDIT_WIDTH - 2) >-#define EDIT_INPUT_WIDTH (EDIT_INTERNAL_WIDTH - 2) >- >-#define EDIT_NAME_LABEL_Y 0 >-#define EDIT_NAME_LABEL_X 0 >-#define EDIT_NAME_LABEL_WIDTH EDIT_INTERNAL_WIDTH >-#define EDIT_NAME_LABEL_HEIGHT 1 >-#define EDIT_NAME_INPUT_Y 1 >-#define EDIT_NAME_INPUT_X 1 >-#define EDIT_NAME_INPUT_WIDTH EDIT_INPUT_WIDTH >-#define EDIT_NAME_INPUT_HEIGHT 1 > >-#define EDIT_DATA_LABEL_Y 3 >-#define EDIT_DATA_LABEL_X 0 >-#define EDIT_DATA_LABEL_WIDTH EDIT_INTERNAL_WIDTH >-#define EDIT_DATA_LABEL_HEIGHT 1 >-#define EDIT_DATA_INPUT_Y 4 >-#define EDIT_DATA_INPUT_X 1 >-#define EDIT_DATA_INPUT_WIDTH EDIT_INPUT_WIDTH >-#define EDIT_DATA_HEIGHT_ONELINE 1 >-#define EDIT_DATA_HEIGHT_MULTILINE 5 >-#define EDIT_DATA_HEIGHT_BUF 10 >- >-#define EDIT_FORM_WIN_Y 0 >-#define EDIT_FORM_WIN_X 0 >-#define EDIT_FORM_WIN_HEIGHT_ONELINE \ >- (EDIT_NAME_LABEL_HEIGHT + EDIT_NAME_INPUT_HEIGHT + 1 + \ >- EDIT_DATA_LABEL_HEIGHT + EDIT_DATA_HEIGHT_ONELINE) >- >-#define EDIT_FORM_WIN_HEIGHT_MULTILINE \ >- (EDIT_NAME_LABEL_HEIGHT + EDIT_NAME_INPUT_HEIGHT + 1 + \ >- EDIT_DATA_LABEL_HEIGHT + EDIT_DATA_HEIGHT_MULTILINE) >- >-#define EDIT_FORM_WIN_HEIGHT_BUF \ >- (EDIT_NAME_LABEL_HEIGHT + EDIT_NAME_INPUT_HEIGHT + 1 + \ >- EDIT_DATA_LABEL_HEIGHT) >- >-#define EDIT_FORM_WIN_WIDTH EDIT_INTERNAL_WIDTH >- >-#define EDIT_PAD 5 >-#define EDIT_HEIGHT_ONELINE (EDIT_FORM_WIN_HEIGHT_ONELINE + EDIT_PAD) >- >-#define EDIT_HEIGHT_MULTILINE (EDIT_FORM_WIN_HEIGHT_MULTILINE + EDIT_PAD) >- >-#define EDIT_HEIGHT_BUF \ >- (EDIT_FORM_WIN_HEIGHT_BUF + EDIT_DATA_HEIGHT_BUF + EDIT_PAD) >- >-#define MAX_FIELDS 5 >-#define FLD_NAME 1 >-#define FLD_DATA 3 >- >-#define DIALOG_RESIZE 2 >- >-enum input_section { >- IN_NAME, >- IN_DATA, >- IN_MENU >-}; >- >-struct edit_dialog { >- struct dialog *dia; >- WINDOW *input_win; >- FORM *input; >- FIELD *field[MAX_FIELDS]; >- struct hexedit *buf; >- enum input_section section; >- bool closing; >+struct edit_req { >+ uint32_t type; > uint32_t mode; >+ struct registry_key *key; >+ const struct value_item *vitem; > }; > >-static int edit_dialog_free(struct edit_dialog *edit) >+static WERROR fill_value_buffer(struct dialog *dia, struct edit_req *edit) > { >- FIELD **f; >+ char *tmp; >+ struct dialog_section *data; > >- if (edit->input) { >- unpost_form(edit->input); >- free_form(edit->input); >- } >- for (f = edit->field; *f; ++f) { >- free_field(*f); >+ if (edit->vitem == NULL) { >+ return WERR_OK; > } >- delwin(edit->input_win); >- >- return 0; >-} > >-static WERROR fill_value_buffer(struct edit_dialog *edit, >- const struct value_item *vitem) >-{ >- char *tmp; >+ data = dialog_find_section(dia, "data"); >+ SMB_ASSERT(data != NULL); > >- switch (vitem->type) { >+ switch (edit->mode) { > case REG_DWORD: { > uint32_t v = 0; >- if (vitem->data.length >= 4) { >- v = IVAL(vitem->data.data, 0); >+ if (edit->vitem->data.length >= 4) { >+ v = IVAL(edit->vitem->data.data, 0); > } >- tmp = talloc_asprintf(edit, "0x%x", v); >+ tmp = talloc_asprintf(dia, "%u", (unsigned)v); > if (tmp == NULL) { > return WERR_NOMEM; > } >- set_field_buffer(edit->field[FLD_DATA], 0, tmp); >+ dialog_section_text_field_set(data, tmp); > talloc_free(tmp); > break; > } >@@ -635,48 +1736,25 @@ static WERROR fill_value_buffer(struct edit_dialog *edit, > case REG_EXPAND_SZ: { > const char *s; > >- if (!pull_reg_sz(edit, &vitem->data, &s)) { >+ if (!pull_reg_sz(dia, &edit->vitem->data, &s)) { > return WERR_NOMEM; > } >- set_field_buffer(edit->field[FLD_DATA], 0, s); >+ dialog_section_text_field_set(data, s); > break; > } > case REG_MULTI_SZ: { >- int rows, cols, max; >- size_t padding, length, index; >- const char **array, **arrayp; >- char *buf = NULL; >+ const char **array; > >- dynamic_field_info(edit->field[FLD_DATA], &rows, &cols, &max); >- if (!pull_reg_multi_sz(edit, &vitem->data, &array)) { >+ if (!pull_reg_multi_sz(dia, &edit->vitem->data, &array)) { > return WERR_NOMEM; > } >- >- /* try to fit each string on it's own line. each line >- needs to be padded with whitespace manually, since >- ncurses fields do not have newlines. */ >- for (index = 0, arrayp = array; *arrayp != NULL; ++arrayp) { >- length = MIN(strlen(*arrayp), cols); >- padding = cols - length; >- buf = talloc_realloc(edit, buf, char, >- talloc_array_length(buf) + >- length + padding + 1); >- if (buf == NULL) { >- return WERR_NOMEM; >- } >- memcpy(&buf[index], *arrayp, length); >- index += length; >- memset(&buf[index], ' ', padding); >- index += padding; >- buf[index] = '\0'; >- } >- >- set_field_buffer(edit->field[FLD_DATA], 0, buf); >- talloc_free(buf); >+ return dialog_section_text_field_set_lines(dia, data, array); > } > case REG_BINARY: >- /* initialized upon dialog creation */ >- break; >+ default: >+ return dialog_section_hexedit_set_buf(data, >+ edit->vitem->data.data, >+ edit->vitem->data.length); > } > > return WERR_OK; >@@ -694,531 +1772,253 @@ static bool value_exists(TALLOC_CTX *ctx, const struct registry_key *key, > return W_ERROR_IS_OK(rv); > } > >-static WERROR set_value(struct edit_dialog *edit, struct registry_key *key, >- uint32_t type, bool new_value) >+static bool edit_on_submit(struct dialog *dia, struct dialog_section *section, >+ void *arg) > { >+ struct edit_req *edit = arg; > WERROR rv; > DATA_BLOB blob; >- char *name = string_trim(edit, field_buffer(edit->field[FLD_NAME], 0)); >- >- if (!new_value && !edit->buf && !field_status(edit->field[FLD_DATA])) { >- return WERR_OK; >- } >- if (new_value && value_exists(edit, key, name)) { >- return WERR_FILE_EXISTS; >+ const char *name; >+ struct dialog_section *name_section, *data; >+ >+ name_section = dialog_find_section(dia, "name"); >+ if (name_section) { >+ name = dialog_section_text_field_get(dia, name_section); >+ if (*name == '\0') { >+ dialog_notice(dia, DIA_ALERT, "Error", >+ "Value name must not be blank."); >+ return false; >+ } >+ if (value_exists(dia, edit->key, name)) { >+ dialog_notice(dia, DIA_ALERT, "Error", >+ "Value named \"%s\" already exists.", >+ name); >+ return false; >+ } >+ } else { >+ SMB_ASSERT(edit->vitem); >+ name = edit->vitem->value_name; > } >+ SMB_ASSERT(name); > >+ data = dialog_find_section(dia, "data"); >+ SMB_ASSERT(data != NULL); >+ >+ rv = WERR_OK; > switch (edit->mode) { > case REG_DWORD: { >+ unsigned long long v; > uint32_t val; >- int base = 10; >- const char *buf = field_buffer(edit->field[FLD_DATA], 0); > >- if (buf[0] == '0' && tolower(buf[1]) == 'x') { >- base = 16; >+ if (!dialog_section_text_field_get_uint(data, &v)) { >+ dialog_notice(dia, DIA_ALERT, "Error", >+ "REG_DWORD value must be an integer."); >+ return false; > } >- >- val = strtoul(buf, NULL, base); >- blob = data_blob_talloc(edit, NULL, sizeof(val)); >+ if (v > UINT32_MAX) { >+ dialog_notice(dia, DIA_ALERT, "Error", >+ "REG_DWORD value must less than %lu.", >+ (unsigned long)UINT32_MAX); >+ return false; >+ } >+ val = (uint32_t)v; >+ blob = data_blob_talloc(dia, NULL, sizeof(val)); > SIVAL(blob.data, 0, val); >- rv = WERR_OK; > break; > } > case REG_SZ: > case REG_EXPAND_SZ: { >- const char *buf = field_buffer(edit->field[FLD_DATA], 0); >- char *str = string_trim(edit, buf); >+ const char *buf; > >- if (!str || !push_reg_sz(edit, &blob, str)) { >+ buf = dialog_section_text_field_get(dia, data); >+ if (!buf || !push_reg_sz(dia, &blob, buf)) { > rv = WERR_NOMEM; > } > break; > } > case REG_MULTI_SZ: { >- int rows, cols, max; >- const char **arr; >- size_t i; >- const char *buf = field_buffer(edit->field[FLD_DATA], 0); >- >- dynamic_field_info(edit->field[FLD_DATA], &rows, &cols, &max); >+ const char **lines; > >- arr = talloc_zero_array(edit, const char *, rows + 1); >- if (arr == NULL) { >- return WERR_NOMEM; >- } >- for (i = 0; *buf; ++i, buf += cols) { >- SMB_ASSERT(i < rows); >- arr[i] = string_trim_n(edit, buf, cols); >- } >- if (!push_reg_multi_sz(edit, &blob, arr)) { >+ lines = dialog_section_text_field_get_lines(dia, data); >+ if (!lines || !push_reg_multi_sz(dia, &blob, lines)) { > rv = WERR_NOMEM; > } > break; > } >- case REG_BINARY: >- blob = data_blob_talloc(edit, NULL, edit->buf->len); >- memcpy(blob.data, edit->buf->data, edit->buf->len); >- break; >- } >- >- rv = reg_val_set(key, name, type, blob); >- >- return rv; >-} >+ case REG_BINARY: { >+ const void *buf; >+ size_t len; > >-static void section_down(struct edit_dialog *edit) >-{ >- switch (edit->section) { >- case IN_NAME: >- if (form_driver(edit->input, REQ_VALIDATION) == E_OK) { >- edit->section = IN_DATA; >- if (edit->buf) { >- hexedit_set_cursor(edit->buf); >- } else { >- set_current_field(edit->input, >- edit->field[FLD_DATA]); >- pos_form_cursor(edit->input); >- } >- } >- break; >- case IN_DATA: >- if (edit->buf || >- form_driver(edit->input, REQ_VALIDATION) == E_OK) { >- edit->section = IN_MENU; >- menu_driver(edit->dia->choices, REQ_FIRST_ITEM); >- pos_menu_cursor(edit->dia->choices); >- } >- break; >- case IN_MENU: >- if (current_item_is_last(edit->dia->choices)) { >- edit->section = IN_NAME; >- set_current_field(edit->input, edit->field[FLD_NAME]); >- pos_form_cursor(edit->input); >- } else { >- menu_driver(edit->dia->choices, REQ_RIGHT_ITEM); >- } >+ dialog_section_hexedit_get_buf(data, &buf, &len); >+ blob = data_blob_talloc(dia, buf, len); > break; > } >-} >- >-static void section_up(struct edit_dialog *edit) >-{ >- switch (edit->section) { >- case IN_NAME: >- if (form_driver(edit->input, REQ_VALIDATION) == E_OK) { >- edit->section = IN_MENU; >- menu_driver(edit->dia->choices, REQ_LAST_ITEM); >- pos_menu_cursor(edit->dia->choices); >- } >- break; >- case IN_DATA: >- if (edit->buf || >- form_driver(edit->input, REQ_VALIDATION) == E_OK) { >- edit->section = IN_NAME; >- set_current_field(edit->input, edit->field[FLD_NAME]); >- pos_form_cursor(edit->input); >- } >- break; >- case IN_MENU: >- if (current_item_is_first(edit->dia->choices)) { >- edit->section = IN_DATA; >- if (edit->buf) { >- hexedit_set_cursor(edit->buf); >- } else { >- set_current_field(edit->input, >- edit->field[FLD_DATA]); >- pos_form_cursor(edit->input); >- } >- } else { >- menu_driver(edit->dia->choices, REQ_LEFT_ITEM); >- } >- break; > } >-} > >-static void handle_hexedit_input(struct hexedit *buf, int c) >-{ >- switch (c) { >- case KEY_UP: >- hexedit_driver(buf, HE_CURSOR_UP); >- break; >- case KEY_DOWN: >- hexedit_driver(buf, HE_CURSOR_DOWN); >- break; >- case KEY_LEFT: >- hexedit_driver(buf, HE_CURSOR_LEFT); >- break; >- case KEY_RIGHT: >- hexedit_driver(buf, HE_CURSOR_RIGHT); >- break; >- default: >- hexedit_driver(buf, c); >- break; >+ if (W_ERROR_IS_OK(rv)) { >+ rv = reg_val_set(edit->key, name, edit->type, blob); > } > >- hexedit_set_cursor(buf); >-} >- >-static WERROR edit_init_dialog(struct edit_dialog *edit, uint32_t type) >-{ >- char *title; >- int diaheight = -1; >- int winheight = -1; >- const char *choices[] = { >- "Ok", >- "Cancel", >- "Resize", >- NULL >- }; >+ if (!W_ERROR_IS_OK(rv)) { >+ const char *msg = get_friendly_werror_msg(rv); >+ dialog_notice(dia, DIA_ALERT, "Error", >+ "Error saving value:\n%s", msg); > >- switch (edit->mode) { >- case REG_MULTI_SZ: >- diaheight = EDIT_HEIGHT_MULTILINE; >- winheight = EDIT_FORM_WIN_HEIGHT_MULTILINE; >- choices[2] = NULL; >- break; >- case REG_BINARY: >- diaheight = EDIT_HEIGHT_BUF; >- winheight = EDIT_FORM_WIN_HEIGHT_BUF; >- break; >- default: >- diaheight = EDIT_HEIGHT_ONELINE; >- winheight = EDIT_FORM_WIN_HEIGHT_ONELINE; >- choices[2] = NULL; >- break; >+ return false; > } > >- title = talloc_asprintf(edit, "Edit %s value", str_regtype(type)); >- if (title == NULL) { >- return WERR_NOMEM; >- } >- edit->dia = dialog_choice_center_new(edit, title, choices, diaheight, >- EDIT_WIDTH); >- talloc_free(title); >- if (edit->dia == NULL) { >- return WERR_NOMEM; >- } >- edit->input_win = derwin(edit->dia->sub_window, winheight, >- EDIT_FORM_WIN_WIDTH, >- EDIT_FORM_WIN_Y, EDIT_FORM_WIN_X); >- if (edit->input_win == NULL) { >- return WERR_NOMEM; >- } >+ return true; > >- return WERR_OK; > } > >-static WERROR edit_init_form(struct edit_dialog *edit, >- const struct value_item *vitem) >+WERROR dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, >+ uint32_t type, const struct value_item *vitem, >+ bool force_binary) > { >+ WERROR err; >+ enum dialog_action action; >+ struct dialog *dia; >+ struct dialog_section *section; >+ struct edit_req edit; >+ struct button_spec spec[] = { >+ {.label = "OK", .action = DIALOG_OK}, >+ {.label = "Cancel", .action = DIALOG_CANCEL}, >+ { 0 } >+ }; > >- edit->field[0] = new_field(EDIT_NAME_LABEL_HEIGHT, >- EDIT_NAME_LABEL_WIDTH, >- EDIT_NAME_LABEL_Y, >- EDIT_NAME_LABEL_X, 0, 0); >- if (edit->field[0] == NULL) { >- return WERR_NOMEM; >- } >- set_field_buffer(edit->field[0], 0, "Name"); >- field_opts_off(edit->field[0], O_EDIT); >- >- edit->field[FLD_NAME] = new_field(EDIT_NAME_INPUT_HEIGHT, >- EDIT_NAME_INPUT_WIDTH, >- EDIT_NAME_INPUT_Y, >- EDIT_NAME_INPUT_X, 0, 0); >- if (edit->field[FLD_NAME] == NULL) { >- return WERR_NOMEM; >- } >- >- edit->field[2] = new_field(EDIT_DATA_LABEL_HEIGHT, >- EDIT_DATA_LABEL_WIDTH, >- EDIT_DATA_LABEL_Y, >- EDIT_DATA_LABEL_X, 0, 0); >- if (edit->field[2] == NULL) { >- return WERR_NOMEM; >+ edit.key = key; >+ edit.vitem = vitem; >+ edit.type = type; >+ edit.mode = type; >+ if (force_binary || (vitem && vitem->unprintable)) { >+ edit.mode = REG_BINARY; > } >- set_field_buffer(edit->field[2], 0, "Data"); >- field_opts_off(edit->field[2], O_EDIT); >- >- if (edit->mode == REG_BINARY) { >- size_t len = 8; >- const void *buf = NULL; >- >- if (vitem) { >- len = vitem->data.length; >- buf = vitem->data.data; >- } >- edit->buf = hexedit_new(edit, edit->dia->sub_window, >- EDIT_DATA_HEIGHT_BUF, >- EDIT_DATA_INPUT_Y, >- EDIT_DATA_INPUT_X, >- buf, len); >- if (edit->buf == NULL) { >- return WERR_NOMEM; >- } >- hexedit_refresh(edit->buf); >- hexedit_set_cursor(edit->buf); >- } else { >- int val_rows = EDIT_DATA_HEIGHT_ONELINE; > >- if (edit->mode == REG_MULTI_SZ) { >- val_rows = EDIT_DATA_HEIGHT_MULTILINE; >- } >- edit->field[FLD_DATA] = new_field(val_rows, >- EDIT_DATA_INPUT_WIDTH, >- EDIT_DATA_INPUT_Y, >- EDIT_DATA_INPUT_X, 0, 0); >- if (edit->field[FLD_DATA] == NULL) { >- return WERR_NOMEM; >- } >- } >+ dia = dialog_new(ctx, PAIR_BLACK_CYAN, "Edit Value", -1, -1); >+ dialog_set_submit_cb(dia, edit_on_submit, &edit); > >- set_field_back(edit->field[FLD_NAME], A_REVERSE); >- field_opts_off(edit->field[FLD_NAME], O_BLANK | O_AUTOSKIP | O_STATIC); >- if (edit->field[FLD_DATA]) { >- set_field_back(edit->field[FLD_DATA], A_REVERSE); >- field_opts_off(edit->field[FLD_DATA], >- O_BLANK | O_AUTOSKIP | O_STATIC | O_WRAP); >- if (edit->mode == REG_DWORD) { >- set_field_type(edit->field[FLD_DATA], TYPE_REGEXP, >- "^ *([0-9]+|0[xX][0-9a-fA-F]+) *$"); >- } >- } >+ section = dialog_section_label_new(dia, "Type"); >+ dialog_append_section(dia, section); >+ section = dialog_section_label_new(dia, "%s", >+ str_regtype(type)); >+ dialog_append_section(dia, section); >+ section = dialog_section_hsep_new(dia, ' '); >+ dialog_append_section(dia, section); > >+ section = dialog_section_label_new(dia, "Name"); >+ dialog_append_section(dia, section); > if (vitem) { >- set_field_buffer(edit->field[FLD_NAME], 0, vitem->value_name); >- field_opts_off(edit->field[FLD_NAME], O_EDIT); >- fill_value_buffer(edit, vitem); >- } >- >- edit->input = new_form(edit->field); >- if (edit->input == NULL) { >- return WERR_NOMEM; >- } >- form_opts_off(edit->input, O_NL_OVERLOAD | O_BS_OVERLOAD); >- >- set_form_win(edit->input, edit->dia->sub_window); >- set_form_sub(edit->input, edit->input_win); >- set_current_field(edit->input, edit->field[FLD_NAME]); >- post_form(edit->input); >- >- return WERR_OK; >-} >- >-static WERROR handle_editor_input(struct edit_dialog *edit, >- struct registry_key *key, >- uint32_t type, >- const struct value_item *vitem, int c) >-{ >- WERROR rv = WERR_OK; >- int selection; >- >- if (edit->section == IN_NAME) { >- handle_form_input(edit->input, c); >- } else if (edit->section == IN_DATA) { >- if (edit->buf) { >- handle_hexedit_input(edit->buf, c); >- } else { >- handle_form_input(edit->input, c); >- } >+ section = dialog_section_label_new(dia, "%s", >+ vitem->value_name); > } else { >- selection = handle_menu_input(edit->dia->choices, c); >- if (selection == DIALOG_OK) { >- rv = set_value(edit, key, type, vitem == NULL); >- if (W_ERROR_EQUAL(rv, WERR_FILE_EXISTS)) { >- dialog_notice(edit, DIA_ALERT, >- "Value exists", >- "Value name already exists."); >- selection = -1; >- } else { >- edit->closing = true; >- } >- } else if (selection == DIALOG_RESIZE) { >- char *n; >- size_t newlen = 0; >- >- dialog_input(edit, &n, "Resize buffer", >- "Enter new size"); >- if (n) { >- newlen = strtoul(n, NULL, 10); >- edit->section = IN_DATA; >- hexedit_resize_buffer(edit->buf, newlen); >- hexedit_refresh(edit->buf); >- hexedit_set_cursor(edit->buf); >- talloc_free(n); >- } >- } else if (selection == DIALOG_CANCEL) { >- edit->closing = true; >- } >- } >- >- return rv; >-} >- >-WERROR dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, >- uint32_t type, const struct value_item *vitem, >- bool force_binary) >-{ >- struct edit_dialog *edit; >- WERROR rv = WERR_NOMEM; >- >- edit = talloc_zero(ctx, struct edit_dialog); >- if (edit == NULL) { >- return rv; >+ section = dialog_section_text_field_new(dia, 1, 50); >+ dialog_section_set_name(section, "name"); > } >- talloc_set_destructor(edit, edit_dialog_free); >+ dialog_append_section(dia, section); >+ section = dialog_section_hsep_new(dia, ' '); >+ dialog_append_section(dia, section); > >- edit->mode = type; >- if (force_binary || (vitem && vitem->unprintable)) { >- edit->mode = REG_BINARY; >- } >+ section = dialog_section_label_new(dia, "Data"); >+ dialog_append_section(dia, section); > >- rv = edit_init_dialog(edit, type); >- if (!W_ERROR_IS_OK(rv)) { >- goto finish; >- } >- rv = edit_init_form(edit, vitem); >- if (!W_ERROR_IS_OK(rv)) { >- goto finish; >+ switch (edit.mode) { >+ case REG_DWORD: >+ case REG_SZ: >+ case REG_EXPAND_SZ: >+ section = dialog_section_text_field_new(dia, 1, 50); >+ break; >+ case REG_MULTI_SZ: >+ section = dialog_section_text_field_new(dia, 10, 50); >+ break; >+ case REG_BINARY: >+ default: >+ section = dialog_section_hexedit_new(dia, 10); >+ break; > } > >- update_panels(); >- doupdate(); >+ dialog_section_set_name(section, "data"); >+ dialog_append_section(dia, section); > >- edit->section = IN_NAME; >- edit->closing = false; >+ section = dialog_section_hsep_new(dia, 0); >+ dialog_append_section(dia, section); >+ section = dialog_section_buttons_new(dia, spec); >+ dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER); >+ dialog_append_section(dia, section); > >- do { >- int c = dialog_getch(edit->dia); >+ dialog_create(dia); > >- if (c == '\t') { >- section_down(edit); >- } else if (c == KEY_BTAB) { >- section_up(edit); >- } else { >- rv = handle_editor_input(edit, key, type, vitem, c); >- } >+ err = fill_value_buffer(dia, &edit); >+ if (!W_ERROR_IS_OK(err)) { >+ return err; >+ } > >- update_panels(); >- doupdate(); >- } while (!edit->closing); >+ dialog_show(dia); >+ dialog_modal_loop(dia, &err, &action); > >-finish: >- talloc_free(edit); >+ talloc_free(dia); > >- return rv; >+ return WERR_OK; > } > > int dialog_select_type(TALLOC_CTX *ctx, int *type) > { >+ WERROR err; >+ enum dialog_action action; > struct dialog *dia; >- const char *choices[] = { >- "OK", >- "Cancel", >- NULL >- }; >+ struct dialog_section *section; > const char *reg_types[] = { >+ "REG_BINARY", > "REG_DWORD", >- "REG_SZ", > "REG_EXPAND_SZ", > "REG_MULTI_SZ", >- "REG_BINARY", >+ "REG_SZ" > }; >-#define NTYPES (sizeof(reg_types) / sizeof(const char*)) >- ITEM **item; >- MENU *list; >- WINDOW *type_win; >- int sel = -1; >- size_t i; >- >- dia = dialog_choice_center_new(ctx, "New Value", choices, 10, 20); >- if (dia == NULL) { >- return -1; >- } >- >- mvwprintw(dia->sub_window, 0, 0, "Choose type:"); >- type_win = derwin(dia->sub_window, 6, 18, 1, 0); >- if (type_win == NULL) { >- goto finish; >- } >- >- item = talloc_zero_array(dia, ITEM *, NTYPES + 1); >- if (item == NULL) { >- goto finish; >- } >+ #define NTYPES ARRAY_SIZE(reg_types) >+ struct button_spec spec[] = { >+ {.label = "OK", .action = DIALOG_OK}, >+ {.label = "Cancel", .action = DIALOG_CANCEL}, >+ { 0 } >+ }; >+ bool flags[NTYPES] = { true }; >+ struct option_spec opsec[NTYPES + 1]; >+ unsigned i; > >+ memset(&opsec, '\0', sizeof(opsec)); > for (i = 0; i < NTYPES; ++i) { >- int t = regtype_by_string(reg_types[i]); >- >- item[i] = new_item(reg_types[i], reg_types[i]); >- if (item[i] == NULL) { >- goto finish; >- } >- set_item_userptr(item[i], (void*)(uintptr_t)t); >- } >- >- list = new_menu(item); >- if (list == NULL) { >- goto finish; >- } >- >- set_menu_format(list, 7, 1); >- set_menu_win(list, dia->sub_window); >- set_menu_sub(list, type_win); >- menu_opts_off(list, O_SHOWDESC); >- set_menu_mark(list, "* "); >- post_menu(list); >- >- update_panels(); >- doupdate(); >- >- while (sel == -1) { >- ITEM *it; >- int c = dialog_getch(dia); >- >- switch (c) { >- case KEY_UP: >- menu_driver(list, REQ_UP_ITEM); >- break; >- case KEY_DOWN: >- menu_driver(list, REQ_DOWN_ITEM); >- break; >- case KEY_LEFT: >- menu_driver(dia->choices, REQ_LEFT_ITEM); >- break; >- case KEY_RIGHT: >- menu_driver(dia->choices, REQ_RIGHT_ITEM); >- break; >- case '\n': >- case KEY_ENTER: >- it = current_item(list); >- *type = (int)(uintptr_t)item_userptr(it); >- it = current_item(dia->choices); >- sel = (int)(uintptr_t)item_userptr(it); >- break; >+ opsec[i].label = reg_types[i]; >+ opsec[i].state = &flags[i]; >+ } >+ >+ dia = dialog_new(ctx, PAIR_BLACK_CYAN, "New Value", -1, -1); >+ >+ section = dialog_section_label_new(dia, "Select type for new value:"); >+ dialog_append_section(dia, section); >+ section = dialog_section_hsep_new(dia, ' '); >+ dialog_append_section(dia, section); >+ section = dialog_section_options_new(dia, opsec, 2, true); >+ dialog_append_section(dia, section); >+ section = dialog_section_hsep_new(dia, 0); >+ dialog_append_section(dia, section); >+ section = dialog_section_buttons_new(dia, spec); >+ dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER); >+ dialog_append_section(dia, section); >+ >+ dialog_create(dia); >+ dialog_show(dia); >+ >+ dialog_modal_loop(dia, &err, &action); >+ if (action == DIALOG_OK) { >+ for (i = 0; i < NTYPES; ++i) { >+ if (flags[i]) { >+ *type = regtype_by_string(reg_types[i]); >+ break; >+ } > } >- >- update_panels(); >- doupdate(); > } > >-finish: >- if (list) { >- unpost_menu(list); >- free_menu(list); >- } >- if (item) { >- ITEM **it; >- for (it = item; *it; ++it) { >- free_item(*it); >- } >- } >- if (type_win) { >- delwin(type_win); >- } > talloc_free(dia); > >- return sel; >+ return action; > } > > int dialog_search_input(TALLOC_CTX *ctx, struct regedit_search_opts *opts) >diff --git a/source3/utils/regedit_dialog.h b/source3/utils/regedit_dialog.h >index f57bcd1..0018f9f 100644 >--- a/source3/utils/regedit_dialog.h >+++ b/source3/utils/regedit_dialog.h >@@ -24,44 +24,190 @@ > #include <panel.h> > #include <menu.h> > >+struct dialog; >+struct dialog_section; >+ >+/* dialog submit cb. return true to close dialog, false to keep >+ it open */ >+typedef bool (*dialog_submit_cb)(struct dialog *, struct dialog_section *, >+ void *); >+ > struct dialog { >+ char *title; > WINDOW *window; >- WINDOW *sub_window; >- WINDOW *menu_window; > PANEL *panel; >- MENU *choices; >- ITEM **choice_items; >+ int x; >+ int y; >+ short color; > bool centered; >+ dialog_submit_cb submit; >+ void *submit_arg; >+ struct dialog_section *head_section; >+ struct dialog_section *tail_section; >+ struct dialog_section *current_section; >+}; >+ >+enum dialog_action { >+ DIALOG_IGNORE, >+ DIALOG_OK, >+ DIALOG_CANCEL > }; > >-struct dialog *dialog_new(TALLOC_CTX *ctx, const char *title, int nlines, >- int ncols, int y, int x); >+struct dialog_section_ops { >+ /* create section */ >+ WERROR (*create)(struct dialog *, struct dialog_section *); >+ >+ /* (optional) cleanup the section */ >+ void (*destroy)(struct dialog_section *); >+ >+ /* (optional) handle character input */ >+ void (*on_input)(struct dialog *, struct dialog_section *, int c); >+ >+ /* (optional) handle a tab character. return true if section dealt >+ with the tab internally, or false to advance focus to >+ the next dialog section. */ >+ bool (*on_tab)(struct dialog *, struct dialog_section *); > >-struct dialog *dialog_center_new(TALLOC_CTX *ctx, const char *title, >- int nlines, int ncols); >+ /* (optional) handle a btab character. return true if section dealt >+ with the tab internally, or false to move focus to >+ the previous dialog section. */ >+ bool (*on_btab)(struct dialog *, struct dialog_section *); > >-struct dialog *dialog_choice_new(TALLOC_CTX *ctx, const char *title, >- const char **choices, int nlines, int ncols, >- int y, int x); >+ /* */ >+ bool (*on_up)(struct dialog *, struct dialog_section *); > >-struct dialog *dialog_choice_center_new(TALLOC_CTX *ctx, const char *title, >- const char **choices, int nlines, >- int ncols); >+ /* */ >+ bool (*on_down)(struct dialog *, struct dialog_section *); >+ >+ /* */ >+ bool (*on_left)(struct dialog *, struct dialog_section *); >+ >+ /* */ >+ bool (*on_right)(struct dialog *, struct dialog_section *); >+ >+ /* (optional) handle enter key. return DIALOG_OK to submit >+ dialog, DIALOG_CANCEL to close dialog, or DIALOG_IGNORE to >+ handle the enter internally. */ >+ enum dialog_action (*on_enter)(struct dialog *, >+ struct dialog_section *); >+ >+ /* (optional) called when this section is about to take focus. forward >+ is set to true when focus has landed here from forward traversal, >+ such as from a tab. return true to accept focus, false to pass to an >+ adjacent section. */ >+ bool (*on_focus)(struct dialog *, struct dialog_section *, bool forward); >+ >+ /* (optional) called when focus is leaving this section */ >+ void (*on_leave_focus)(struct dialog *, struct dialog_section *); >+}; >+ >+enum section_justify { >+ SECTION_JUSTIFY_LEFT, >+ SECTION_JUSTIFY_CENTER, >+ SECTION_JUSTIFY_RIGHT, >+}; >+ >+struct dialog_section { >+ char *name; >+ int nlines; >+ int ncols; >+ WINDOW *window; >+ enum section_justify justify; >+ const struct dialog_section_ops *ops; >+ struct dialog_section *next; >+ struct dialog_section *prev; >+}; >+ >+struct dialog *dialog_new(TALLOC_CTX *ctx, short color, >+ const char *title, int y, int x); >+ >+void dialog_section_destroy(struct dialog_section *section); >+void dialog_section_init(struct dialog_section *section, >+ const struct dialog_section_ops *ops, >+ int nlines, int ncols); >+ >+void dialog_section_set_name(struct dialog_section *section, const char *name); >+const char *dialog_section_get_name(struct dialog_section *section); >+void dialog_section_set_justify(struct dialog_section *section, >+ enum section_justify justify); >+ >+void dialog_append_section(struct dialog *dia, >+ struct dialog_section *section); >+struct dialog_section *dialog_find_section(struct dialog *dia, >+ const char *name); >+ >+WERROR dialog_create(struct dialog *dia); >+void dialog_show(struct dialog *dia); >+void dialog_destroy(struct dialog *dia); >+void dialog_set_submit_cb(struct dialog *dia, dialog_submit_cb cb, void *arg); >+bool dialog_handle_input(struct dialog *dia, WERROR *err, >+ enum dialog_action *action); >+void dialog_modal_loop(struct dialog *dia, WERROR *err, >+ enum dialog_action *action); >+ >+struct dialog_section *dialog_section_label_new_va(TALLOC_CTX *ctx, >+ const char *msg, va_list ap); >+struct dialog_section *dialog_section_label_new(TALLOC_CTX *ctx, >+ const char *msg, ...); >+ >+struct dialog_section *dialog_section_hsep_new(TALLOC_CTX *ctx, int sep); >+ >+ >+struct dialog_section *dialog_section_text_field_new(TALLOC_CTX *ctx, >+ int height, int width); >+const char *dialog_section_text_field_get(TALLOC_CTX *ctx, >+ struct dialog_section *section); >+const char **dialog_section_text_field_get_lines(TALLOC_CTX *ctx, >+ struct dialog_section *section); >+bool dialog_section_text_field_get_int(struct dialog_section *section, >+ long long *out); >+bool dialog_section_text_field_get_uint(struct dialog_section *section, >+ unsigned long long *out); >+void dialog_section_text_field_set(struct dialog_section *section, >+ const char *s); >+WERROR dialog_section_text_field_set_lines(TALLOC_CTX *ctx, >+ struct dialog_section *section, >+ const char **array); >+ >+struct dialog_section *dialog_section_hexedit_new(TALLOC_CTX *ctx, int height); >+WERROR dialog_section_hexedit_set_buf(struct dialog_section *section, >+ const void *data, size_t size); >+void dialog_section_hexedit_get_buf(struct dialog_section *section, >+ const void **data, size_t *size); >+ >+struct button_spec { >+ const char *label; >+ enum dialog_action (*on_enter)(struct dialog *, >+ struct dialog_section *); >+ enum dialog_action action; >+ >+ /* internal */ >+ int col; >+}; >+struct dialog_section *dialog_section_buttons_new(TALLOC_CTX *ctx, >+ const struct button_spec *spec); >+ >+struct option_spec { >+ const char *label; >+ bool *state; >+ >+ /* internal */ >+ int col; >+ int row; >+}; >+struct dialog_section *dialog_section_options_new(TALLOC_CTX *ctx, >+ const struct option_spec *spec, >+ int maxcol, bool single_select); > > enum dialog_type { > DIA_ALERT, > DIA_CONFIRM > }; > >-enum dialog_selection { >- DIALOG_OK = 0, >- DIALOG_CANCEL = 1 >-}; >- > int dialog_notice(TALLOC_CTX *ctx, enum dialog_type type, > const char *title, const char *msg, ...); > >-int dialog_input(TALLOC_CTX *ctx, char **output, const char *title, >+int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title, > const char *msg, ...); > > struct registry_key; >-- >2.1.1 > > >From 7f5fc8dbe0d185067d5575b8940eb57767d3583c Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Sat, 26 Jul 2014 19:49:33 -0700 >Subject: [PATCH 28/45] regedit: move cursor to edited value in list and report > edit errors > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 061d3e9a66f7f71cc6532fa6b0bcf47bf0fe3e35) >--- > source3/utils/regedit.c | 41 ++++++++++++++++++++++++++++----------- > source3/utils/regedit_dialog.c | 26 ++++++++++++++++--------- > source3/utils/regedit_dialog.h | 7 ++++--- > source3/utils/regedit_valuelist.c | 22 +++++++++++++++++++++ > source3/utils/regedit_valuelist.h | 4 ++++ > 5 files changed, 77 insertions(+), 23 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 5b7885c..cc3598b 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -406,6 +406,8 @@ static void handle_value_input(struct regedit *regedit, int c) > { > struct value_item *vitem; > bool binmode = false; >+ WERROR err; >+ int sel; > > switch (c) { > case KEY_DOWN: >@@ -423,26 +425,45 @@ static void handle_value_input(struct regedit *regedit, int c) > vitem = value_list_get_current_item(regedit->vl); > if (vitem) { > struct tree_node *node; >+ const char *name = NULL; > node = tree_view_get_current_node(regedit->keys); >- dialog_edit_value(regedit, node->key, vitem->type, >- vitem, binmode); >- tree_node_reopen_key(node); >- value_list_load(regedit->vl, node->key); >+ sel = dialog_edit_value(regedit, node->key, vitem->type, >+ vitem, binmode, &err, &name); >+ if (!W_ERROR_IS_OK(err)) { >+ const char *msg = get_friendly_werror_msg(err); >+ dialog_notice(regedit, DIA_ALERT, "Error", >+ "Error editing value:\n%s", msg); >+ } else if (sel == DIALOG_OK) { >+ tree_node_reopen_key(node); >+ value_list_load(regedit->vl, node->key); >+ value_list_set_current_item_by_name(regedit->vl, >+ name); >+ talloc_free(discard_const(name)); >+ } > } > break; > case 'n': > case 'N': { > int new_type; >- int sel; > > sel = dialog_select_type(regedit, &new_type); > if (sel == DIALOG_OK) { > struct tree_node *node; >+ const char *name = NULL; > node = tree_view_get_current_node(regedit->keys); >- dialog_edit_value(regedit, node->key, new_type, NULL, >- false); >- tree_node_reopen_key(node); >- value_list_load(regedit->vl, node->key); >+ sel = dialog_edit_value(regedit, node->key, new_type, >+ NULL, false, &err, &name); >+ if (!W_ERROR_IS_OK(err)) { >+ const char *msg = get_friendly_werror_msg(err); >+ dialog_notice(regedit, DIA_ALERT, "Error", >+ "Error creating value:\n%s", msg); >+ } else if (sel == DIALOG_OK) { >+ tree_node_reopen_key(node); >+ value_list_load(regedit->vl, node->key); >+ value_list_set_current_item_by_name(regedit->vl, >+ name); >+ talloc_free(discard_const(name)); >+ } > } > break; > } >@@ -450,8 +471,6 @@ static void handle_value_input(struct regedit *regedit, int c) > case 'D': > vitem = value_list_get_current_item(regedit->vl); > if (vitem) { >- int sel; >- > sel = dialog_notice(regedit, DIA_CONFIRM, > "Delete Value", > "Really delete value \"%s\"?", >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index 119219d..3cef7a0 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -1871,11 +1871,11 @@ static bool edit_on_submit(struct dialog *dia, struct dialog_section *section, > > } > >-WERROR dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, >- uint32_t type, const struct value_item *vitem, >- bool force_binary) >+int dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, >+ uint32_t type, const struct value_item *vitem, >+ bool force_binary, WERROR *err, >+ const char **name) > { >- WERROR err; > enum dialog_action action; > struct dialog *dia; > struct dialog_section *section; >@@ -1947,17 +1947,25 @@ WERROR dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, > > dialog_create(dia); > >- err = fill_value_buffer(dia, &edit); >- if (!W_ERROR_IS_OK(err)) { >- return err; >+ *err = fill_value_buffer(dia, &edit); >+ if (!W_ERROR_IS_OK(*err)) { >+ return DIALOG_CANCEL; > } > > dialog_show(dia); >- dialog_modal_loop(dia, &err, &action); >+ dialog_modal_loop(dia, err, &action); >+ >+ if (action == DIALOG_OK && name) { >+ if (vitem) { >+ *name = talloc_strdup(ctx, vitem->value_name); >+ } else if ((section = dialog_find_section(dia, "name"))) { >+ *name = dialog_section_text_field_get(ctx, section); >+ } >+ } > > talloc_free(dia); > >- return WERR_OK; >+ return action; > } > > int dialog_select_type(TALLOC_CTX *ctx, int *type) >diff --git a/source3/utils/regedit_dialog.h b/source3/utils/regedit_dialog.h >index 0018f9f..c0d89ff 100644 >--- a/source3/utils/regedit_dialog.h >+++ b/source3/utils/regedit_dialog.h >@@ -213,9 +213,10 @@ int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title, > struct registry_key; > struct value_item; > >-WERROR dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, >- uint32_t type, const struct value_item *vitem, >- bool force_binary); >+int dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, >+ uint32_t type, const struct value_item *vitem, >+ bool force_binary, WERROR *err, >+ const char **name); > > int dialog_select_type(TALLOC_CTX *ctx, int *type); > >diff --git a/source3/utils/regedit_valuelist.c b/source3/utils/regedit_valuelist.c >index 9557c8c..aa387a7 100644 >--- a/source3/utils/regedit_valuelist.c >+++ b/source3/utils/regedit_valuelist.c >@@ -392,6 +392,28 @@ struct value_item *value_list_get_current_item(struct value_list *vl) > multilist_get_current_row(vl->list)); > } > >+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, item); >+} >+ >+void value_list_set_current_item(struct value_list *vl, >+ const struct value_item *item) >+{ >+ multilist_set_current_row(vl->list, item); >+} >+ > void value_list_driver(struct value_list *vl, int c) > { > multilist_driver(vl->list, c); >diff --git a/source3/utils/regedit_valuelist.h b/source3/utils/regedit_valuelist.h >index ea67075..b84b4ff 100644 >--- a/source3/utils/regedit_valuelist.h >+++ b/source3/utils/regedit_valuelist.h >@@ -52,6 +52,10 @@ 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); > struct value_item *value_list_get_current_item(struct value_list *vl); >+void value_list_set_current_item(struct value_list *vl, >+ const struct value_item *item); >+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); > > #endif >-- >2.1.1 > > >From 7ecc5393665d402bf833ed4c6c5668ad6936d193 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Sun, 27 Jul 2014 17:39:06 -0700 >Subject: [PATCH 29/45] regedit: use the right function to reopen a hive > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 1b6445ae03521d788bf247eb550d1b51113fc8df) >--- > source3/utils/regedit.c | 15 ++++++++++----- > source3/utils/regedit_treeview.c | 17 ++++++++++++++--- > source3/utils/regedit_treeview.h | 3 ++- > 3 files changed, 26 insertions(+), 9 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index cc3598b..d77c2e4 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -187,7 +187,8 @@ static void add_reg_key(struct regedit *regedit, struct tree_node *node, > } else { > /* Reopen the parent key to make sure the > new subkey will be noticed. */ >- tree_node_reopen_key(parent); >+ tree_node_reopen_key(regedit->registry_context, >+ parent); > } > > list = tree_node_first(node); >@@ -377,7 +378,8 @@ static void handle_tree_input(struct regedit *regedit, int c) > > rv = reg_key_del(node, parent->key, node->name); > if (W_ERROR_IS_OK(rv)) { >- tree_node_reopen_key(parent); >+ tree_node_reopen_key(regedit->registry_context, >+ parent); > tree_view_clear(regedit->keys); > pop = tree_node_pop(&node); > talloc_free(pop); >@@ -434,7 +436,8 @@ static void handle_value_input(struct regedit *regedit, int c) > dialog_notice(regedit, DIA_ALERT, "Error", > "Error editing value:\n%s", msg); > } else if (sel == DIALOG_OK) { >- tree_node_reopen_key(node); >+ tree_node_reopen_key(regedit->registry_context, >+ node); > value_list_load(regedit->vl, node->key); > value_list_set_current_item_by_name(regedit->vl, > name); >@@ -458,7 +461,8 @@ static void handle_value_input(struct regedit *regedit, int c) > dialog_notice(regedit, DIA_ALERT, "Error", > "Error creating value:\n%s", msg); > } else if (sel == DIALOG_OK) { >- tree_node_reopen_key(node); >+ tree_node_reopen_key(regedit->registry_context, >+ node); > value_list_load(regedit->vl, node->key); > value_list_set_current_item_by_name(regedit->vl, > name); >@@ -480,7 +484,8 @@ static void handle_value_input(struct regedit *regedit, int c) > node = tree_view_get_current_node(regedit->keys); > reg_del_value(regedit, node->key, > vitem->value_name); >- tree_node_reopen_key(node); >+ tree_node_reopen_key(regedit->registry_context, >+ node); > value_list_load(regedit->vl, node->key); > } > } >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index 47d9282..885e6d0 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -197,13 +197,24 @@ static uint32_t get_num_subkeys(struct tree_node *node) > return 0; > } > >-WERROR tree_node_reopen_key(struct tree_node *node) >+WERROR tree_node_reopen_key(struct registry_context *ctx, >+ struct tree_node *node) > { > SMB_ASSERT(node->parent != NULL); > SMB_ASSERT(node->name != NULL); > TALLOC_FREE(node->key); >- return reg_open_key(node->parent, node->parent->key, node->name, >- &node->key); >+ >+ if (tree_node_is_top_level(node)) { >+ WERROR rv; >+ struct registry_key *key; >+ rv = reg_get_predefined_key_by_name(ctx, node->name, &key); >+ if (W_ERROR_IS_OK(rv)) { >+ node->key = talloc_steal(node, key); >+ } >+ return rv; >+ } >+ >+ return reg_open_key(node, node->parent->key, node->name, &node->key); > } > > bool tree_node_has_children(struct tree_node *node) >diff --git a/source3/utils/regedit_treeview.h b/source3/utils/regedit_treeview.h >index 4d1851a..919507f 100644 >--- a/source3/utils/regedit_treeview.h >+++ b/source3/utils/regedit_treeview.h >@@ -74,7 +74,8 @@ void tree_view_clear(struct tree_view *view); > WERROR tree_view_set_root(struct tree_view *view, struct tree_node *root); > WERROR tree_view_set_path(struct tree_view *view, const char **path); > WERROR tree_view_update(struct tree_view *view, struct tree_node *list); >-WERROR tree_node_reopen_key(struct tree_node *node); >+WERROR tree_node_reopen_key(struct registry_context *ctx, >+ struct tree_node *node); > bool tree_node_has_children(struct tree_node *node); > WERROR tree_node_load_children(struct tree_node *node); > void tree_node_insert_sorted(struct tree_node *list, struct tree_node *node); >-- >2.1.1 > > >From 0355ae24828cab54c20fcace0913db5b5b1c6033 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Sun, 27 Jul 2014 17:48:05 -0700 >Subject: [PATCH 30/45] regedit: clear value list after creating new key > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit cc22cb5cd44fdcc078211d2b82502ca219b1e928) >--- > source3/utils/regedit.c | 1 + > 1 file changed, 1 insertion(+) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index d77c2e4..3ff833a 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -198,6 +198,7 @@ static void add_reg_key(struct regedit *regedit, struct tree_node *node, > node = new_node; > } > tree_view_set_current_node(regedit->keys, node); >+ load_values(regedit); > } else { > msg = get_friendly_werror_msg(rv); > dialog_notice(regedit, DIA_ALERT, "New Key", >-- >2.1.1 > > >From a78090bbe9498a2a7bbb09f09310e916723a957c Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Mon, 28 Jul 2014 23:04:10 -0700 >Subject: [PATCH 31/45] regedit: use pad as a canvas for dialogs > >Drawing in a pad allows the dialog to maintain the same size even when >the terminal window is shrunk to some awkwardly small size. It also >helps avoid hacks needed to update positions of subwindows when the >panel is moved. > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit c272178ccc6bb2f3b4a6621ef463489741c7e040) >--- > source3/utils/regedit_dialog.c | 79 ++++++++++++++++++++++++++++++------------ > source3/utils/regedit_dialog.h | 1 + > 2 files changed, 57 insertions(+), 23 deletions(-) > >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index 3cef7a0..d8ffa9f 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -343,6 +343,11 @@ WERROR dialog_create(struct dialog *dia) > /* create window for dialog */ > nlines += 4; > ncols += 6; >+ dia->pad = newpad(nlines, ncols); >+ if (dia->pad == NULL) { >+ rv = WERR_NOMEM; >+ goto fail; >+ } > dia->centered = false; > if (dia->y < 0 || dia->x < 0) { > dia->centered = true; >@@ -360,18 +365,19 @@ WERROR dialog_create(struct dialog *dia) > } > > /* setup color and border */ >- wbkgdset(dia->window, ' ' | COLOR_PAIR(dia->color)); >- wclear(dia->window); >- mvwhline(dia->window, 1, 2, 0, ncols - 4); >- mvwhline(dia->window, nlines - 2, 2, 0, ncols - 4); >- mvwvline(dia->window, 2, 1, 0, nlines - 4); >- mvwvline(dia->window, 2, ncols - 2, 0, nlines - 4); >- mvwaddch(dia->window, 1, 1, ACS_ULCORNER); >- mvwaddch(dia->window, 1, ncols - 2, ACS_URCORNER); >- mvwaddch(dia->window, nlines - 2, 1, ACS_LLCORNER); >- mvwaddch(dia->window, nlines - 2, ncols - 2, ACS_LRCORNER); >+ getmaxyx(dia->pad, nlines, ncols); >+ wbkgdset(dia->pad, ' ' | COLOR_PAIR(dia->color)); >+ wclear(dia->pad); >+ mvwhline(dia->pad, 1, 2, 0, ncols - 4); >+ mvwhline(dia->pad, nlines - 2, 2, 0, ncols - 4); >+ mvwvline(dia->pad, 2, 1, 0, nlines - 4); >+ mvwvline(dia->pad, 2, ncols - 2, 0, nlines - 4); >+ mvwaddch(dia->pad, 1, 1, ACS_ULCORNER); >+ mvwaddch(dia->pad, 1, ncols - 2, ACS_URCORNER); >+ mvwaddch(dia->pad, nlines - 2, 1, ACS_LLCORNER); >+ mvwaddch(dia->pad, nlines - 2, ncols - 2, ACS_LRCORNER); > col = ncols / 2 - MIN(strlen(dia->title) + 2, ncols) / 2; >- mvwprintw(dia->window, 1, col, " %s ", dia->title); >+ mvwprintw(dia->pad, 1, col, " %s ", dia->title); > > /* create subwindows for each section */ > row = 2; >@@ -389,7 +395,7 @@ WERROR dialog_create(struct dialog *dia) > break; > } > >- section->window = derwin(dia->window, section->nlines, >+ section->window = subpad(dia->pad, section->nlines, > section->ncols, row, col); > if (section->window == NULL) { > rv = WERR_NOMEM; >@@ -410,15 +416,30 @@ fail: > > void dialog_show(struct dialog *dia) > { >- struct dialog_section *section; >+ int nlines, ncols; >+ int pad_y, pad_x; >+ int y, x; >+ int rv; > >+ touchwin(dia->pad); >+ getmaxyx(dia->window, nlines, ncols); >+ getmaxyx(dia->pad, pad_y, pad_x); >+ y = 0; >+ if (pad_y > nlines) { >+ y = (pad_y - nlines) / 2; >+ } >+ x = 0; >+ if (pad_x > ncols) { >+ x = (pad_x - ncols) / 2; >+ } >+ rv = copywin(dia->pad, dia->window, y, x, 0, 0, >+ nlines - 1, ncols - 1, false); >+ SMB_ASSERT(rv == OK); >+ >+ getyx(dia->pad, pad_y, pad_x); >+ wmove(dia->window, pad_y - y, pad_x - x); > touchwin(dia->window); > wnoutrefresh(dia->window); >- section = dia->head_section; >- do { >- wnoutrefresh(section->window); >- section = section->next; >- } while (section != dia->head_section); > } > > void dialog_destroy(struct dialog *dia) >@@ -448,9 +469,16 @@ static int dialog_getch(struct dialog *dia) > c = regedit_getch(); > if (c == KEY_RESIZE) { > int nlines, ncols, y, x; >+ int pad_nlines, pad_ncols; >+ int win_nlines, win_ncols; > >- getmaxyx(dia->window, nlines, ncols); >+ getmaxyx(dia->window, win_nlines, win_ncols); >+ getmaxyx(dia->pad, pad_nlines, pad_ncols); > getbegyx(dia->window, y, x); >+ >+ nlines = pad_nlines; >+ ncols = pad_ncols; >+ > if (dia->centered) { > center_above_window(&nlines, &ncols, &y, &x); > } else { >@@ -469,6 +497,10 @@ static int dialog_getch(struct dialog *dia) > } > } > } >+ if (nlines != win_nlines || ncols != win_ncols) { >+ wresize(dia->window, nlines, ncols); >+ replace_panel(dia->panel, dia->window); >+ } > move_panel(dia->panel, y, x); > } > >@@ -542,6 +574,7 @@ void dialog_modal_loop(struct dialog *dia, WERROR *err, > enum dialog_action *action) > { > do { >+ dialog_show(dia); > update_panels(); > doupdate(); > } while (dialog_handle_input(dia, err, action)); >@@ -649,10 +682,10 @@ static WERROR hsep_create(struct dialog *dia, struct dialog_section *section) > /* change the border characters around this section to > tee chars */ > getparyx(section->window, y, x); >- mvwaddch(dia->window, y, x - 1, ACS_HLINE); >- mvwaddch(dia->window, y, x - 2, ACS_LTEE); >- mvwaddch(dia->window, y, x + section->ncols, ACS_HLINE); >- mvwaddch(dia->window, y, x + section->ncols + 1, ACS_RTEE); >+ mvwaddch(dia->pad, y, x - 1, ACS_HLINE); >+ mvwaddch(dia->pad, y, x - 2, ACS_LTEE); >+ mvwaddch(dia->pad, y, x + section->ncols, ACS_HLINE); >+ mvwaddch(dia->pad, y, x + section->ncols + 1, ACS_RTEE); > } > > return WERR_OK; >diff --git a/source3/utils/regedit_dialog.h b/source3/utils/regedit_dialog.h >index c0d89ff..18b9b98 100644 >--- a/source3/utils/regedit_dialog.h >+++ b/source3/utils/regedit_dialog.h >@@ -35,6 +35,7 @@ typedef bool (*dialog_submit_cb)(struct dialog *, struct dialog_section *, > struct dialog { > char *title; > WINDOW *window; >+ WINDOW *pad; > PANEL *panel; > int x; > int y; >-- >2.1.1 > > >From 00534bc6ca7cddfa2823ef12a86764f5335c7c3c Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Mon, 28 Jul 2014 23:23:32 -0700 >Subject: [PATCH 32/45] regedit: don't use subwindows in hexedit > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 982c06f55a0ef8a80a0f87c9e77200ce952f85b3) >--- > source3/utils/regedit_dialog.c | 4 ++-- > source3/utils/regedit_hexedit.c | 45 ++++++++++------------------------------- > source3/utils/regedit_hexedit.h | 4 ++-- > 3 files changed, 15 insertions(+), 38 deletions(-) > >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index d8ffa9f..3c57773 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -1037,8 +1037,8 @@ static WERROR hexedit_create(struct dialog *dia, > struct dialog_section_hexedit *hexedit = > talloc_get_type_abort(section, struct dialog_section_hexedit); > >- hexedit->buf = hexedit_new(dia, section->window, section->nlines, >- 0, 0, NULL, HEXEDIT_MIN_SIZE); >+ hexedit->buf = hexedit_new(dia, section->window, NULL, >+ HEXEDIT_MIN_SIZE); > if (hexedit->buf == NULL) { > return WERR_NOMEM; > } >diff --git a/source3/utils/regedit_hexedit.c b/source3/utils/regedit_hexedit.c >index 847c5d8..bdc4255 100644 >--- a/source3/utils/regedit_hexedit.c >+++ b/source3/utils/regedit_hexedit.c >@@ -44,32 +44,19 @@ struct hexedit { > int nibble; > uint8_t *data; > WINDOW *win; >- WINDOW *status_line; > }; > > static int max_rows(WINDOW *win) > { >- int maxy, maxx; >+ int maxy; > >- getmaxyx(win, maxy, maxx); >+ maxy = getmaxy(win); > > return maxy - 1; > } > >-static int hexedit_free(struct hexedit *buf) >-{ >- if (buf->status_line) { >- delwin(buf->status_line); >- } >- if (buf->win) { >- delwin(buf->win); >- } >- >- return 0; >-} >- >-struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines, >- int y, int x, const void *data, size_t sz) >+struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, const void *data, >+ size_t sz) > { > WERROR rv; > struct hexedit *buf; >@@ -79,19 +66,7 @@ struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines, > return NULL; > } > >- talloc_set_destructor(buf, hexedit_free); >- >- buf->win = derwin(parent, nlines, LINE_WIDTH, y, x); >- if (buf->win == NULL) { >- goto fail; >- } >- >- buf->status_line = derwin(buf->win, 1, LINE_WIDTH, max_rows(buf->win), >- 0); >- if (buf->status_line == NULL) { >- goto fail; >- } >- wattron(buf->status_line, A_REVERSE | A_STANDOUT); >+ buf->win = parent; > > rv = hexedit_set_buf(buf, data, sz); > if (!W_ERROR_IS_OK(rv)) { >@@ -147,18 +122,20 @@ static size_t bytes_per_screen(WINDOW *win) > > void hexedit_set_cursor(struct hexedit *buf) > { >- werase(buf->status_line); >+ wmove(buf->win, max_rows(buf->win), 0); >+ wattron(buf->win, A_REVERSE | A_STANDOUT); >+ wclrtoeol(buf->win); > if (buf->len) { >- wprintw(buf->status_line, "Len:%lu Off:%lu Val:0x%X", buf->len, >+ wprintw(buf->win, "Len:%lu Off:%lu Val:0x%X", buf->len, > buf->cursor_offset, buf->data[buf->cursor_offset]); > } else { >- wprintw(buf->status_line, "Len:%lu (empty)", buf->len); >+ wprintw(buf->win, "Len:%lu (empty)", buf->len); > } >+ wattroff(buf->win, A_REVERSE | A_STANDOUT); > wmove(buf->win, buf->cursor_y, buf->cursor_x); > wcursyncup(buf->win); > wsyncup(buf->win); > untouchwin(buf->win); >- wnoutrefresh(buf->status_line); > } > > void hexedit_refresh(struct hexedit *buf) >diff --git a/source3/utils/regedit_hexedit.h b/source3/utils/regedit_hexedit.h >index af2432a..dc13c21 100644 >--- a/source3/utils/regedit_hexedit.h >+++ b/source3/utils/regedit_hexedit.h >@@ -34,8 +34,8 @@ enum { > #define LINE_WIDTH 44 > struct hexedit; > >-struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines, >- int y, int x, const void *data, size_t sz); >+struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, const void *data, >+ size_t sz); > WERROR hexedit_set_buf(struct hexedit *buf, const void *data, size_t sz); > const void *hexedit_get_buf(struct hexedit *buf); > size_t hexedit_get_buf_len(struct hexedit *buf); >-- >2.1.1 > > >From af6eb2058a37e699d2aa8442fdaae3908f15b5a1 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Wed, 30 Jul 2014 22:04:50 -0700 >Subject: [PATCH 33/45] regedit: flesh out search dialog and simplify search > opts > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 09245177a4031fb1a1319071e745f0df10b1ee53) >--- > source3/utils/regedit.c | 11 ++---- > source3/utils/regedit.h | 9 ++--- > source3/utils/regedit_dialog.c | 86 ++++++++++++++++++++++++++++++++++++++---- > 3 files changed, 87 insertions(+), 19 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 3ff833a..c1b94ac 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -537,18 +537,15 @@ static void handle_main_input(struct regedit *regedit, int c) > struct regedit_search_opts *opts; > > opts = ®edit->active_search; >- if (opts->query) { >- talloc_free(discard_const(opts->query)); >- } > rv = dialog_search_input(regedit, opts); > if (rv == DIALOG_OK) { > SMB_ASSERT(opts->query != NULL); >- opts->match = find_substring; >+ opts->match = find_substring_nocase; > opts->node = regedit->keys->root; >- if (opts->search_nocase) { >- opts->match = find_substring_nocase; >+ if (opts->search_case) { >+ opts->match = find_substring; > } >- if (opts->search_relative) { >+ if (!opts->search_recursive) { > opts->node = > tree_view_get_current_node(regedit->keys); > } >diff --git a/source3/utils/regedit.h b/source3/utils/regedit.h >index 688bc72..c99aeba 100644 >--- a/source3/utils/regedit.h >+++ b/source3/utils/regedit.h >@@ -65,11 +65,10 @@ struct regedit_search_opts { > const char *query; > regedit_search_match_fn_t match; > struct tree_node *node; >- unsigned int search_key:1; >- unsigned int search_value:1; >- unsigned int search_recursive:1; >- unsigned int search_relative:1; >- unsigned int search_nocase:1; >+ bool search_key; >+ bool search_value; >+ bool search_recursive; >+ bool search_case; > }; > > #define PAIR_YELLOW_CYAN 1 >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index 3c57773..20d7651 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -2062,16 +2062,88 @@ int dialog_select_type(TALLOC_CTX *ctx, int *type) > return action; > } > >+struct search_req { >+ TALLOC_CTX *ctx; >+ struct regedit_search_opts *opts; >+}; >+ >+static bool search_on_submit(struct dialog *dia, struct dialog_section *section, >+ void *arg) >+{ >+ struct search_req *search = arg; >+ struct dialog_section *query; >+ >+ query = dialog_find_section(dia, "query"); >+ SMB_ASSERT(query != NULL); >+ >+ if (!search->opts->search_key && !search->opts->search_value) { >+ dialog_notice(dia, DIA_ALERT, "Error", >+ "Must search a key and/or a value"); >+ return false; >+ } >+ >+ talloc_free(discard_const(search->opts->query)); >+ search->opts->query = dialog_section_text_field_get(search->ctx, query); >+ SMB_ASSERT(search->opts->query != NULL); >+ if (search->opts->query[0] == '\0') { >+ dialog_notice(dia, DIA_ALERT, "Error", >+ "Query must not be blank."); >+ return false; >+ } >+ >+ return true; >+} >+ > int dialog_search_input(TALLOC_CTX *ctx, struct regedit_search_opts *opts) > { >- int rv; >- // TODO >+ WERROR err; >+ enum dialog_action action; >+ struct dialog *dia; >+ struct dialog_section *section, *query; >+ struct search_req search; >+ struct button_spec spec[] = { >+ {.label = "Search", .action = DIALOG_OK}, >+ {.label = "Cancel", .action = DIALOG_CANCEL}, >+ { 0 } >+ }; >+ struct option_spec search_opts[] = { >+ {.label = "Search Keys", .state = &opts->search_key}, >+ {.label = "Search Values", .state = &opts->search_value}, >+ {.label = "Recursive", .state = &opts->search_recursive}, >+ {.label = "Case Sensitive", .state = &opts->search_case}, >+ { 0 } >+ }; >+ >+ if (!opts->search_key && !opts->search_value) { >+ opts->search_key = true; >+ } >+ >+ search.ctx = ctx; >+ search.opts = opts; >+ dia = dialog_new(ctx, PAIR_BLACK_CYAN, "Search", -1, -1); >+ dialog_set_submit_cb(dia, search_on_submit, &search); >+ section = dialog_section_label_new(dia, "Query"); >+ dialog_append_section(dia, section); >+ query = dialog_section_text_field_new(dia, 1, -1); >+ dialog_section_set_name(query, "query"); >+ dialog_append_section(dia, query); >+ section = dialog_section_hsep_new(dia, 0); >+ dialog_append_section(dia, section); >+ section = dialog_section_options_new(dia, search_opts, 2, false); >+ dialog_append_section(dia, section); >+ section = dialog_section_hsep_new(dia, 0); >+ dialog_append_section(dia, section); >+ section = dialog_section_buttons_new(dia, spec); >+ dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER); >+ dialog_append_section(dia, section); > >- opts->search_key = 1; >- opts->search_recursive = 1; >- opts->search_nocase = 1; >+ dialog_create(dia); >+ if (opts->query) { >+ dialog_section_text_field_set(query, opts->query); >+ } > >- rv = dialog_input(ctx, &opts->query, "Search", "Query"); >+ dialog_modal_loop(dia, &err, &action); >+ talloc_free(dia); > >- return rv; >+ return action; > } >-- >2.1.1 > > >From d3a75bbb458a12592c635e2bd6e2357ef175804e Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Thu, 31 Jul 2014 23:24:19 -0700 >Subject: [PATCH 34/45] 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> >(cherry picked from commit bcab659516382d5dc51b1558a895a9a26d81c6b8) >--- > source3/utils/regedit.c | 186 ++++++++++++++++++++++++-------------- > source3/utils/regedit.h | 1 - > source3/utils/regedit_treeview.c | 47 ++++++++++ > source3/utils/regedit_treeview.h | 1 + > source3/utils/regedit_valuelist.c | 100 +++++++++++++++++--- > source3/utils/regedit_valuelist.h | 13 ++- > 6 files changed, 265 insertions(+), 83 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index c1b94ac..a5fb913 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 = ®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,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 = ®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; >diff --git a/source3/utils/regedit.h b/source3/utils/regedit.h >index c99aeba..0928f9e 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 885e6d0..cf071de 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 919507f..ba0cd0a 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 aa387a7..f12a81e 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 b84b4ff..1178389 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 >-- >2.1.1 > > >From 4e934e82abad977593c9d16d2dd3b5b249fe09ba Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Sat, 2 Aug 2014 17:29:31 -0700 >Subject: [PATCH 35/45] regedit: find previous items > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit fd95b0aa96067d4c9ce60b73168bf9fe5c95ffac) >--- > source3/utils/regedit.c | 28 +++++++++++++++++++-------- > source3/utils/regedit_treeview.c | 41 ++++++++++++++++++++++++++++++++++++++++ > source3/utils/regedit_treeview.h | 1 + > 3 files changed, 62 insertions(+), 8 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index a5fb913..34a63d7 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -222,6 +222,11 @@ static WERROR regedit_search(struct regedit *regedit, struct tree_node *node, > bool search_key, need_sync; > char *save_value_name; > WERROR rv; >+ bool (*iterate)(struct tree_node **, bool, WERROR *); >+ struct value_item *(*find_item)(struct value_list *, >+ struct value_item *, >+ const char *, >+ regedit_search_match_fn_t); > > opts = ®edit->active_search; > >@@ -237,6 +242,13 @@ static WERROR regedit_search(struct regedit *regedit, struct tree_node *node, > save_value_name = NULL; > search_key = opts->search_key; > need_sync = false; >+ iterate = tree_node_next; >+ find_item = value_list_find_next_item; >+ >+ if (flags & SEARCH_PREV) { >+ iterate = tree_node_prev; >+ find_item = value_list_find_prev_item; >+ } > > if (opts->search_value) { > struct value_item *it; >@@ -258,7 +270,7 @@ static WERROR regedit_search(struct regedit *regedit, struct tree_node *node, > if (!vitem && (flags & SEARCH_REPEAT)) { > if (opts->search_value) { > search_key = false; >- } else if (!tree_node_next(&node, opts->search_recursive, &rv)) { >+ } else if (!iterate(&node, opts->search_recursive, &rv)) { > beep(); > return rv; > } >@@ -283,10 +295,8 @@ static WERROR regedit_search(struct regedit *regedit, struct tree_node *node, > } > need_sync = true; > } >- found_value = value_list_find_next_item(regedit->vl, >- vitem, >- opts->query, >- opts->match); >+ found_value = find_item(regedit->vl, vitem, opts->query, >+ opts->match); > if (found_value) { > found = node; > } else { >@@ -294,7 +304,7 @@ static WERROR regedit_search(struct regedit *regedit, struct tree_node *node, > search_key = opts->search_key; > } > } >- } while (!found && tree_node_next(&node, opts->search_recursive, &rv)); >+ } while (!found && iterate(&node, opts->search_recursive, &rv)); > > if (!W_ERROR_IS_OK(rv)) { > goto out; >@@ -589,7 +599,7 @@ static void handle_main_input(struct regedit *regedit, int c) > if (rv == DIALOG_OK) { > SMB_ASSERT(opts->query != NULL); > opts->match = find_substring_nocase; >- node = regedit->keys->root; >+ node = regedit->keys->root->child_head; > if (opts->search_case) { > opts->match = find_substring; > } >@@ -602,9 +612,11 @@ static void handle_main_input(struct regedit *regedit, int c) > break; > } > case 'x': >- case 'X': > regedit_search_repeat(regedit, SEARCH_NEXT); > break; >+ case 'X': >+ regedit_search_repeat(regedit, SEARCH_PREV); >+ break; > case '\t': > regedit->tree_input = !regedit->tree_input; > print_heading(regedit); >diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c >index cf071de..4c68fea 100644 >--- a/source3/utils/regedit_treeview.c >+++ b/source3/utils/regedit_treeview.c >@@ -342,6 +342,30 @@ static WERROR next_depth_first(struct tree_node **node) > return rv; > } > >+static WERROR prev_depth_first(struct tree_node **node) >+{ >+ WERROR rv = WERR_OK; >+ >+ SMB_ASSERT(node != NULL && *node != NULL); >+ >+ if ((*node)->previous) { >+ *node = (*node)->previous; >+ while (tree_node_has_children(*node)) { >+ rv = tree_node_load_children(*node); >+ if (W_ERROR_IS_OK(rv)) { >+ SMB_ASSERT((*node)->child_head != NULL); >+ *node = tree_node_last((*node)->child_head); >+ } >+ } >+ } else if (!tree_node_is_top_level(*node)) { >+ *node = (*node)->parent; >+ } else { >+ *node = NULL; >+ } >+ >+ return rv; >+} >+ > bool tree_node_next(struct tree_node **node, bool depth, WERROR *err) > { > *err = WERR_OK; >@@ -359,6 +383,23 @@ bool tree_node_next(struct tree_node **node, bool depth, WERROR *err) > return *node != NULL && W_ERROR_IS_OK(*err); > } > >+bool tree_node_prev(struct tree_node **node, bool depth, WERROR *err) >+{ >+ *err = WERR_OK; >+ >+ if (*node == NULL) { >+ return false; >+ } >+ >+ if (depth) { >+ *err = prev_depth_first(node); >+ } else { >+ *node = (*node)->previous; >+ } >+ >+ 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 ba0cd0a..4b892bb 100644 >--- a/source3/utils/regedit_treeview.h >+++ b/source3/utils/regedit_treeview.h >@@ -61,6 +61,7 @@ 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); >+bool tree_node_prev(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); >-- >2.1.1 > > >From d770b0414cc8b60485b2d81b1f4a7ce4b6eaebda Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Wed, 6 Aug 2014 20:15:38 -0700 >Subject: [PATCH 36/45] regedit: adjust some variable names to make them more > distinct > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 58db858619339084c86a02fd226eaff0854c730f) >--- > source3/utils/regedit_dialog.c | 38 +++++++++++++++++++------------------- > 1 file changed, 19 insertions(+), 19 deletions(-) > >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index 20d7651..6ab550b 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -1223,7 +1223,7 @@ static void buttons_unhighlight(struct dialog_section_buttons *buttons) > > static void buttons_highlight(struct dialog_section_buttons *buttons) > { >- struct button_spec *button = &buttons->spec[buttons->current_button]; >+ struct button_spec *spec = &buttons->spec[buttons->current_button]; > short pair; > attr_t attr; > >@@ -1235,9 +1235,9 @@ static void buttons_highlight(struct dialog_section_buttons *buttons) > */ > (wattr_get)(buttons->section.window, &attr, &pair, NULL); > mvwchgat(buttons->section.window, 0, 0, -1, A_NORMAL, pair, NULL); >- mvwchgat(buttons->section.window, 0, button->col, >- strlen(button->label), A_REVERSE, pair, NULL); >- wmove(buttons->section.window, 0, button->col + 2); >+ mvwchgat(buttons->section.window, 0, spec->col, >+ strlen(spec->label), A_REVERSE, pair, NULL); >+ wmove(buttons->section.window, 0, spec->col + 2); > wcursyncup(buttons->section.window); > wnoutrefresh(buttons->section.window); > } >@@ -1271,8 +1271,8 @@ static WERROR buttons_create(struct dialog *dia, > > nbuttons = talloc_array_length(buttons->spec); > for (i = 0; i < nbuttons; ++i) { >- struct button_spec *button = &buttons->spec[i]; >- mvwaddstr(section->window, 0, button->col, button->label); >+ struct button_spec *spec = &buttons->spec[i]; >+ mvwaddstr(section->window, 0, spec->col, spec->label); > } > > buttons->current_button = 0; >@@ -1428,7 +1428,7 @@ static void options_unhighlight(struct dialog_section_options *options) > > static void options_highlight(struct dialog_section_options *options) > { >- struct option_spec *option = &options->spec[options->current_option]; >+ struct option_spec *spec = &options->spec[options->current_option]; > short pair; > attr_t attr; > size_t row; >@@ -1443,9 +1443,9 @@ static void options_highlight(struct dialog_section_options *options) > for (row = 0; row < options->section.nlines; ++row) { > mvwchgat(options->section.window, row, 0, -1, A_NORMAL, pair, NULL); > } >- mvwchgat(options->section.window, option->row, option->col, >- strlen(option->label), A_REVERSE, pair, NULL); >- wmove(options->section.window, option->row, option->col + 4); >+ mvwchgat(options->section.window, spec->row, spec->col, >+ strlen(spec->label), A_REVERSE, pair, NULL); >+ wmove(options->section.window, spec->row, spec->col + 4); > wcursyncup(options->section.window); > wnoutrefresh(options->section.window); > } >@@ -1456,12 +1456,12 @@ static void options_render_state(struct dialog_section_options *options) > > noptions = talloc_array_length(options->spec); > for (i = 0; i < noptions; ++i) { >- struct option_spec *option = &options->spec[i]; >+ struct option_spec *spec = &options->spec[i]; > char c = ' '; >- if (*option->state) >+ if (*spec->state) > c = 'x'; > mvwaddch(options->section.window, >- option->row, option->col + 1, c); >+ spec->row, spec->col + 1, c); > wnoutrefresh(options->section.window); > } > } >@@ -1487,7 +1487,7 @@ static bool options_highlight_previous(struct dialog_section_options *options) > } > > static WERROR options_create(struct dialog *dia, >- struct dialog_section *section) >+ struct dialog_section *section) > { > size_t i, noptions; > struct dialog_section_options *options = >@@ -1495,9 +1495,9 @@ static WERROR options_create(struct dialog *dia, > > noptions = talloc_array_length(options->spec); > for (i = 0; i < noptions; ++i) { >- struct option_spec *option = &options->spec[i]; >- mvwaddstr(section->window, option->row, option->col, >- option->label); >+ struct option_spec *spec = &options->spec[i]; >+ mvwaddstr(section->window, spec->row, spec->col, >+ spec->label); > } > > options->current_option = 0; >@@ -1528,7 +1528,7 @@ static void options_on_input(struct dialog *dia, struct dialog_section *section, > talloc_get_type_abort(section, struct dialog_section_options); > > if (c == ' ') { >- struct option_spec *option = &options->spec[options->current_option]; >+ struct option_spec *spec = &options->spec[options->current_option]; > if (options->single_select) { > size_t i, noptions; > noptions = talloc_array_length(options->spec); >@@ -1536,7 +1536,7 @@ static void options_on_input(struct dialog *dia, struct dialog_section *section, > *(options->spec[i].state) = false; > } > } >- *option->state = !*option->state; >+ *spec->state = !*spec->state; > options_unhighlight(options); > options_render_state(options); > options_highlight(options); >-- >2.1.1 > > >From d1460c8e6e6fb3dea6372ccf3af3cf358e3be361 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Fri, 8 Aug 2014 19:58:03 -0700 >Subject: [PATCH 37/45] regedit: handle DEL key in text fields > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 00765544af53cdfcc6f602b1825f14b97b96beb1) >--- > source3/utils/regedit_dialog.c | 3 +++ > 1 file changed, 3 insertions(+) > >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index 6ab550b..b807c4e 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -777,6 +777,9 @@ static void text_field_on_input(struct dialog *dia, > case KEY_BACKSPACE: > form_driver(text_field->form, REQ_DEL_PREV); > break; >+ case KEY_DC: >+ form_driver(text_field->form, REQ_DEL_CHAR); >+ break; > default: > form_driver(text_field->form, c); > break; >-- >2.1.1 > > >From 8693571eb93e5f440e4661cedaf714dc935825bc Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Fri, 8 Aug 2014 22:25:50 -0700 >Subject: [PATCH 38/45] regedit: don't expand single line text field buffer > with cursor movement > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 5bbed3d93dfddb0386401a032dc3321bc7f67e33) >--- > source3/utils/regedit_dialog.c | 25 ++++++++++++++++++++++++- > 1 file changed, 24 insertions(+), 1 deletion(-) > >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index b807c4e..b5ab400 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -721,8 +721,18 @@ struct dialog_section_text_field { > unsigned opts; > FIELD *field[2]; > FORM *form; >+ int length; > }; > >+static int get_cursor_col(struct dialog_section_text_field *field) >+{ >+ int col; >+ >+ col = field->form->curcol + field->form->begincol; >+ >+ return col; >+} >+ > static WERROR text_field_create(struct dialog *dia, > struct dialog_section *section) > { >@@ -775,12 +785,20 @@ static void text_field_on_input(struct dialog *dia, > > switch (c) { > case KEY_BACKSPACE: >+ if (text_field->length) { >+ text_field->length--; >+ } > form_driver(text_field->form, REQ_DEL_PREV); > break; >+ case '\x7f': > case KEY_DC: >+ if (text_field->length) { >+ text_field->length--; >+ } > form_driver(text_field->form, REQ_DEL_CHAR); > break; > default: >+ text_field->length++; > form_driver(text_field->form, c); > break; > } >@@ -829,7 +847,10 @@ static bool text_field_on_right(struct dialog *dia, > struct dialog_section_text_field *text_field = > talloc_get_type_abort(section, struct dialog_section_text_field); > >- form_driver(text_field->form, REQ_RIGHT_CHAR); >+ if (section->nlines > 1 || >+ get_cursor_col(text_field) < text_field->length) { >+ form_driver(text_field->form, REQ_RIGHT_CHAR); >+ } > > return true; > } >@@ -841,6 +862,7 @@ static enum dialog_action text_field_on_enter(struct dialog *dia, > talloc_get_type_abort(section, struct dialog_section_text_field); > > if (section->nlines > 1) { >+ text_field->length += text_field->form->cols; > form_driver(text_field->form, REQ_NEW_LINE); > return DIALOG_IGNORE; > } >@@ -911,6 +933,7 @@ void dialog_section_text_field_set(struct dialog_section *section, > struct dialog_section_text_field *text_field = > talloc_get_type_abort(section, struct dialog_section_text_field); > >+ text_field->length = strlen(s); > set_field_buffer(text_field->field[0], 0, s); > } > >-- >2.1.1 > > >From d757550db0e7a99be8621611c9b9b3745454ab31 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Fri, 8 Aug 2014 23:36:48 -0700 >Subject: [PATCH 39/45] regedit: add a number input box > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 8acb87e42e8004c6a2f04085825fadad3cfbc5b2) >--- > source3/utils/regedit_dialog.c | 124 +++++++++++++++++++++++++++++++++++++---- > source3/utils/regedit_dialog.h | 4 ++ > 2 files changed, 116 insertions(+), 12 deletions(-) > >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index b5ab400..dff44ea 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -1675,11 +1675,75 @@ fail: > } > > >-int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title, >- const char *msg, ...) >+enum input_type { >+ DLG_IN_LONG, >+ DLG_IN_ULONG, >+ DLG_IN_STR, >+}; >+ >+struct input_req { >+ TALLOC_CTX *ctx; >+ enum input_type type; >+ union { >+ void *out; >+ unsigned long *out_ulong; >+ long *out_long; >+ const char **out_str; >+ } out; >+}; >+ >+static bool input_on_submit(struct dialog *dia, struct dialog_section *section, >+ void *arg) >+{ >+ struct input_req *req = arg; >+ struct dialog_section *data; >+ unsigned long long out_ulong; >+ long long out_long; >+ >+ data = dialog_find_section(dia, "input"); >+ >+ switch (req->type) { >+ case DLG_IN_LONG: >+ if (!dialog_section_text_field_get_int(data, &out_long)) { >+ dialog_notice(dia, DIA_ALERT, "Error", >+ "Input must be a number."); >+ return false; >+ } >+ if (out_long < LONG_MIN || out_long > LONG_MAX) { >+ dialog_notice(dia, DIA_ALERT, "Error", >+ "Number is out of range."); >+ return false; >+ } >+ *req->out.out_long = out_long; >+ break; >+ case DLG_IN_ULONG: >+ if (!dialog_section_text_field_get_uint(data, &out_ulong)) { >+ dialog_notice(dia, DIA_ALERT, "Error", >+ "Input must be a number greater than zero."); >+ return false; >+ } >+ if (out_ulong > ULONG_MAX) { >+ dialog_notice(dia, DIA_ALERT, "Error", >+ "Number is out of range."); >+ return false; >+ } >+ *req->out.out_ulong = out_ulong; >+ break; >+ case DLG_IN_STR: >+ *req->out.out_str = dialog_section_text_field_get(req->ctx, data); >+ break; >+ } >+ >+ return true; >+} >+ >+static int dialog_input_internal(TALLOC_CTX *ctx, void *output, >+ enum input_type type, >+ const char *title, >+ const char *msg, va_list ap) > { >- va_list ap; > WERROR err; >+ struct input_req req; > enum dialog_action action; > struct dialog *dia; > struct dialog_section *section; >@@ -1689,10 +1753,14 @@ int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title, > { 0 } > }; > >+ req.ctx = ctx; >+ req.type = type; >+ req.out.out = output; >+ *req.out.out_str = NULL; >+ > dia = dialog_new(ctx, PAIR_BLACK_CYAN, title, -1, -1); >- va_start(ap, msg); >+ dialog_set_submit_cb(dia, input_on_submit, &req); > section = dialog_section_label_new_va(dia, msg, ap); >- va_end(ap); > dialog_append_section(dia, section); > section = dialog_section_hsep_new(dia, ' '); > dialog_append_section(dia, section); >@@ -1708,18 +1776,50 @@ int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title, > dialog_create(dia); > dialog_show(dia); > dialog_modal_loop(dia, &err, &action); >- >- *output = NULL; >- if (action == DIALOG_OK) { >- section = dialog_find_section(dia, "input"); >- *output = dialog_section_text_field_get(ctx, section); >- } >- > talloc_free(dia); > > return action; > } > >+int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title, >+ const char *msg, ...) >+{ >+ va_list ap; >+ int rv; >+ >+ va_start(ap, msg); >+ rv = dialog_input_internal(ctx, output, DLG_IN_STR, title, msg, ap); >+ va_end(ap); >+ >+ return rv; >+} >+ >+int dialog_input_ulong(TALLOC_CTX *ctx, unsigned long *output, >+ const char *title, const char *msg, ...) >+{ >+ va_list ap; >+ int rv; >+ >+ va_start(ap, msg); >+ rv = dialog_input_internal(ctx, output, DLG_IN_ULONG, title, msg, ap); >+ va_end(ap); >+ >+ return rv; >+} >+ >+int dialog_input_long(TALLOC_CTX *ctx, long *output, >+ const char *title, const char *msg, ...) >+{ >+ va_list ap; >+ int rv; >+ >+ va_start(ap, msg); >+ rv = dialog_input_internal(ctx, output, DLG_IN_LONG, title, msg, ap); >+ va_end(ap); >+ >+ return rv; >+} >+ > int dialog_notice(TALLOC_CTX *ctx, enum dialog_type type, > const char *title, const char *msg, ...) > { >diff --git a/source3/utils/regedit_dialog.h b/source3/utils/regedit_dialog.h >index 18b9b98..283e0e2 100644 >--- a/source3/utils/regedit_dialog.h >+++ b/source3/utils/regedit_dialog.h >@@ -210,6 +210,10 @@ int dialog_notice(TALLOC_CTX *ctx, enum dialog_type type, > > int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title, > const char *msg, ...); >+int dialog_input_long(TALLOC_CTX *ctx, long *output, >+ const char *title, const char *msg, ...); >+int dialog_input_ulong(TALLOC_CTX *ctx, unsigned long *output, >+ const char *title, const char *msg, ...); > > struct registry_key; > struct value_item; >-- >2.1.1 > > >From 4395aef745b03179a47841aecf9fca216036498b Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Fri, 8 Aug 2014 23:55:25 -0700 >Subject: [PATCH 40/45] regedit: add a button to resize hexedit buffer > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 4badab3a6062a473b9651564ce43bb51c63457c1) >--- > source3/utils/regedit_dialog.c | 48 ++++++++++++++++++++++++++++++++++++++++-- > source3/utils/regedit_dialog.h | 2 ++ > 2 files changed, 48 insertions(+), 2 deletions(-) > >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index dff44ea..6f0aeda 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -1224,6 +1224,23 @@ void dialog_section_hexedit_get_buf(struct dialog_section *section, > *size = hexedit_get_buf_len(hexedit->buf); > } > >+WERROR dialog_section_hexedit_resize(struct dialog_section *section, >+ size_t size) >+{ >+ WERROR rv; >+ struct dialog_section_hexedit *hexedit = >+ talloc_get_type_abort(section, struct dialog_section_hexedit); >+ >+ SMB_ASSERT(hexedit->buf != NULL); >+ rv = hexedit_resize_buffer(hexedit->buf, size); >+ if (W_ERROR_IS_OK(rv)) { >+ hexedit_refresh(hexedit->buf); >+ } >+ >+ return rv; >+} >+ >+ > /* button box */ > struct dialog_section_buttons { > struct dialog_section section; >@@ -2030,6 +2047,22 @@ static bool edit_on_submit(struct dialog *dia, struct dialog_section *section, > > } > >+static enum dialog_action edit_on_resize(struct dialog *dia, >+ struct dialog_section *section) >+{ >+ struct dialog_section *data; >+ unsigned long size; >+ int rv; >+ >+ data = dialog_find_section(dia, "data"); >+ rv = dialog_input_ulong(dia, &size, "Resize", "Enter size of buffer"); >+ if (rv == DIALOG_OK) { >+ dialog_section_hexedit_resize(data, size); >+ } >+ >+ return DIALOG_IGNORE; >+} >+ > int dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, > uint32_t type, const struct value_item *vitem, > bool force_binary, WERROR *err, >@@ -2039,11 +2072,18 @@ int dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, > struct dialog *dia; > struct dialog_section *section; > struct edit_req edit; >- struct button_spec spec[] = { >+ struct button_spec buttons[] = { > {.label = "OK", .action = DIALOG_OK}, > {.label = "Cancel", .action = DIALOG_CANCEL}, > { 0 } > }; >+ struct button_spec buttons_hexedit[] = { >+ {.label = "OK", .action = DIALOG_OK}, >+ {.label = "Resize Buffer", .on_enter = edit_on_resize}, >+ {.label = "Cancel", .action = DIALOG_CANCEL}, >+ { 0 } >+ }; >+ > > edit.key = key; > edit.vitem = vitem; >@@ -2100,7 +2140,11 @@ int dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, > > section = dialog_section_hsep_new(dia, 0); > dialog_append_section(dia, section); >- section = dialog_section_buttons_new(dia, spec); >+ if (edit.mode == REG_BINARY) { >+ section = dialog_section_buttons_new(dia, buttons_hexedit); >+ } else { >+ section = dialog_section_buttons_new(dia, buttons); >+ } > dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER); > dialog_append_section(dia, section); > >diff --git a/source3/utils/regedit_dialog.h b/source3/utils/regedit_dialog.h >index 283e0e2..5c7c84a 100644 >--- a/source3/utils/regedit_dialog.h >+++ b/source3/utils/regedit_dialog.h >@@ -175,6 +175,8 @@ WERROR dialog_section_hexedit_set_buf(struct dialog_section *section, > const void *data, size_t size); > void dialog_section_hexedit_get_buf(struct dialog_section *section, > const void **data, size_t *size); >+WERROR dialog_section_hexedit_resize(struct dialog_section *section, >+ size_t size); > > struct button_spec { > const char *label; >-- >2.1.1 > > >From 32a18fd381eab2935ac3f26063dff9e4abda94c0 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Sat, 9 Aug 2014 13:39:59 -0700 >Subject: [PATCH 41/45] regedit: grow hexedit buffer as the user types > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 3c6541c44e2bfca2d1dfb7a971064d2c7143106f) >--- > source3/utils/regedit_dialog.c | 2 +- > source3/utils/regedit_hexedit.c | 68 +++++++++++++++++++++++++++-------------- > 2 files changed, 46 insertions(+), 24 deletions(-) > >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index 6f0aeda..3dc18dd 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -1056,7 +1056,7 @@ struct dialog_section_hexedit { > struct hexedit *buf; > }; > >-#define HEXEDIT_MIN_SIZE 16 >+#define HEXEDIT_MIN_SIZE 1 > static WERROR hexedit_create(struct dialog *dia, > struct dialog_section *section) > { >diff --git a/source3/utils/regedit_hexedit.c b/source3/utils/regedit_hexedit.c >index bdc4255..8a7c8a1 100644 >--- a/source3/utils/regedit_hexedit.c >+++ b/source3/utils/regedit_hexedit.c >@@ -223,17 +223,6 @@ static int offset_to_hex_col(size_t pos) > return -1; > } > >-static bool scroll_down(struct hexedit *buf) >-{ >- if (buf->offset + bytes_per_screen(buf->win) >= buf->len) { >- return false; >- } >- >- buf->offset += BYTES_PER_LINE; >- >- return true; >-} >- > static bool scroll_up(struct hexedit *buf) > { > if (buf->offset == 0) { >@@ -247,17 +236,34 @@ static bool scroll_up(struct hexedit *buf) > > static void cursor_down(struct hexedit *buf) > { >+ size_t space; >+ bool need_refresh = false; >+ >+ space = buf->offset + (buf->cursor_y + 1) * BYTES_PER_LINE; >+ if (space > buf->len) { >+ return; >+ } >+ > if (buf->cursor_y + 1 == max_rows(buf->win)) { >- if (scroll_down(buf)) { >- hexedit_refresh(buf); >- } >+ buf->offset += BYTES_PER_LINE; >+ need_refresh = true; > } else { >- if (buf->cursor_offset + BYTES_PER_LINE >= buf->len) { >- return; >- } > buf->cursor_y++; > } > >+ if (buf->cursor_offset + BYTES_PER_LINE > buf->len) { >+ buf->nibble = 0; >+ buf->cursor_offset = buf->len; >+ buf->cursor_line_offset = buf->len - space; >+ if (buf->cursor_x >= ASCII_COL) { >+ buf->cursor_x = ASCII_COL + buf->cursor_line_offset; >+ } else { >+ buf->cursor_x = offset_to_hex_col(buf->cursor_line_offset); >+ } >+ } >+ if (need_refresh) { >+ hexedit_refresh(buf); >+ } > calc_cursor_offset(buf); > } > >@@ -308,7 +314,7 @@ static void cursor_left(struct hexedit *buf) > } else if (buf->cursor_x == ASCII_COL) { > size_t off = buf->offset + buf->cursor_y * BYTES_PER_LINE; > if (off + 7 >= buf->len) { >- size_t lastpos = buf->len - off - 1; >+ size_t lastpos = buf->len - off; > buf->cursor_x = offset_to_hex_col(lastpos) + 1; > buf->cursor_line_offset = lastpos; > } else { >@@ -342,7 +348,7 @@ static void cursor_right(struct hexedit *buf) > return; > } > if ((buf->cursor_x >= ASCII_COL || buf->nibble == 1) && >- buf->cursor_offset + 1 == buf->len) { >+ buf->cursor_offset == buf->len) { > if (buf->cursor_x < ASCII_COL) { > new_x = ASCII_COL; > buf->cursor_line_offset = 0; >@@ -383,6 +389,10 @@ static void do_edit(struct hexedit *buf, int c) > return; > } > >+ if (buf->cursor_offset == buf->len) { >+ hexedit_resize_buffer(buf, buf->len + 1); >+ } >+ > byte = buf->data + buf->cursor_offset; > > if (buf->cursor_x >= ASCII_COL) { >@@ -395,7 +405,11 @@ static void do_edit(struct hexedit *buf, int c) > } > mvwaddch(buf->win, buf->cursor_y, > ASCII_COL + buf->cursor_line_offset, c); >- cursor_right(buf); >+ if (buf->cursor_x + 1 != ASCII_COL_END) { >+ cursor_right(buf); >+ } else { >+ cursor_down(buf); >+ } > } else { > if (!isxdigit(c)) { > return; >@@ -423,8 +437,12 @@ static void do_edit(struct hexedit *buf, int c) > > if (buf->cursor_x + 1 != HEX_COL2_END) { > cursor_right(buf); >+ } else { >+ cursor_down(buf); > } > } >+ >+ hexedit_refresh(buf); > } > > void hexedit_driver(struct hexedit *buf, int c) >@@ -458,7 +476,7 @@ WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz) > { > /* reset the cursor if it'll be out of bounds > after the resize */ >- if (buf->cursor_offset >= newsz) { >+ if (buf->cursor_offset > newsz) { > buf->cursor_y = 0; > buf->cursor_x = HEX_COL1; > buf->offset = 0; >@@ -470,12 +488,16 @@ WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz) > if (newsz > buf->len) { > if (newsz > buf->alloc_size) { > uint8_t *d; >- d = talloc_realloc(buf, buf->data, uint8_t, newsz); >+ buf->alloc_size *= 2; >+ if (newsz > buf->alloc_size) { >+ buf->alloc_size = newsz; >+ } >+ d = talloc_realloc(buf, buf->data, uint8_t, >+ buf->alloc_size); > if (d == NULL) { > return WERR_NOMEM; > } > buf->data = d; >- buf->alloc_size = newsz; > } > memset(buf->data + buf->len, '\0', newsz - buf->len); > buf->len = newsz; >-- >2.1.1 > > >From 3024abd70548dc8f569043b6cc686aad973de82f Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Sat, 9 Aug 2014 17:11:00 -0700 >Subject: [PATCH 42/45] regedit: handle del and backspace in hexeditor > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit b96c43219480c442d0264834101e5bee675e3b04) >--- > source3/utils/regedit_dialog.c | 6 +++- > source3/utils/regedit_hexedit.c | 72 +++++++++++++++++++++++++++++++++++------ > source3/utils/regedit_hexedit.h | 4 ++- > 3 files changed, 71 insertions(+), 11 deletions(-) > >diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c >index 3dc18dd..d0b486f 100644 >--- a/source3/utils/regedit_dialog.c >+++ b/source3/utils/regedit_dialog.c >@@ -1093,7 +1093,11 @@ static void hexedit_on_input(struct dialog *dia, > > switch (c) { > case KEY_BACKSPACE: >- // FIXME hexedit_driver(hexedit->buf, c); >+ hexedit_driver(hexedit->buf, HE_BACKSPACE); >+ break; >+ case '\x7f': >+ case KEY_DC: >+ hexedit_driver(hexedit->buf, HE_DELETE); > break; > default: > hexedit_driver(hexedit->buf, c); >diff --git a/source3/utils/regedit_hexedit.c b/source3/utils/regedit_hexedit.c >index 8a7c8a1..377eef9 100644 >--- a/source3/utils/regedit_hexedit.c >+++ b/source3/utils/regedit_hexedit.c >@@ -125,11 +125,12 @@ void hexedit_set_cursor(struct hexedit *buf) > wmove(buf->win, max_rows(buf->win), 0); > wattron(buf->win, A_REVERSE | A_STANDOUT); > wclrtoeol(buf->win); >- if (buf->len) { >+ if (buf->cursor_offset < buf->len) { > wprintw(buf->win, "Len:%lu Off:%lu Val:0x%X", buf->len, > buf->cursor_offset, buf->data[buf->cursor_offset]); > } else { >- wprintw(buf->win, "Len:%lu (empty)", buf->len); >+ wprintw(buf->win, "Len:%lu Off:%lu", buf->len, >+ buf->cursor_offset); > } > wattroff(buf->win, A_REVERSE | A_STANDOUT); > wmove(buf->win, buf->cursor_y, buf->cursor_x); >@@ -341,9 +342,6 @@ static void cursor_right(struct hexedit *buf) > { > int new_x = buf->cursor_x + 1; > >- if (buf->len == 0) { >- return; >- } > if (new_x == ASCII_COL_END) { > return; > } >@@ -385,10 +383,6 @@ static void do_edit(struct hexedit *buf, int c) > { > uint8_t *byte; > >- if (buf->len == 0) { >- return; >- } >- > if (buf->cursor_offset == buf->len) { > hexedit_resize_buffer(buf, buf->len + 1); > } >@@ -445,6 +439,60 @@ static void do_edit(struct hexedit *buf, int c) > hexedit_refresh(buf); > } > >+static void erase_at(struct hexedit *buf, size_t pos) >+{ >+ if (pos >= buf->len) { >+ return; >+ } >+ >+ if (pos < buf->len - 1) { >+ /* squeeze the character out of the buffer */ >+ uint8_t *p = buf->data + pos; >+ uint8_t *end = buf->data + buf->len; >+ memmove(p, p + 1, end - p - 1); >+ } >+ >+ buf->len--; >+ hexedit_refresh(buf); >+} >+ >+static void do_backspace(struct hexedit *buf) >+{ >+ size_t off; >+ bool erase = true; >+ >+ if (buf->cursor_offset == 0) { >+ return; >+ } >+ >+ off = buf->cursor_offset; >+ if (buf->cursor_x == ASCII_COL) { >+ cursor_up(buf); >+ buf->cursor_line_offset = 7; >+ buf->cursor_x = ASCII_COL_END - 1; >+ calc_cursor_offset(buf); >+ } else if (buf->cursor_x == HEX_COL1) { >+ cursor_up(buf); >+ buf->cursor_line_offset = 7; >+ buf->cursor_x = HEX_COL2_END - 1; >+ buf->nibble = 1; >+ calc_cursor_offset(buf); >+ } else { >+ if (buf->cursor_x < ASCII_COL && buf->nibble) { >+ erase = false; >+ } >+ cursor_left(buf); >+ } >+ if (erase) { >+ erase_at(buf, off - 1); >+ } >+} >+ >+static void do_delete(struct hexedit *buf) >+{ >+ erase_at(buf, buf->cursor_offset); >+} >+ > void hexedit_driver(struct hexedit *buf, int c) > { > switch (c) { >@@ -464,6 +512,12 @@ void hexedit_driver(struct hexedit *buf, int c) > break; > case HE_CURSOR_PGDN: > break; >+ case HE_BACKSPACE: >+ do_backspace(buf); >+ break; >+ case HE_DELETE: >+ do_delete(buf); >+ break; > default: > do_edit(buf, c & 0xff); > break; >diff --git a/source3/utils/regedit_hexedit.h b/source3/utils/regedit_hexedit.h >index dc13c21..dfbe27a 100644 >--- a/source3/utils/regedit_hexedit.h >+++ b/source3/utils/regedit_hexedit.h >@@ -28,7 +28,9 @@ enum { > HE_CURSOR_LEFT = 0x1200, > HE_CURSOR_RIGHT = 0x1300, > HE_CURSOR_PGUP = 0x1400, >- HE_CURSOR_PGDN = 0x1500 >+ HE_CURSOR_PGDN = 0x1500, >+ HE_BACKSPACE = 0x1600, >+ HE_DELETE = 0x1700, > }; > > #define LINE_WIDTH 44 >-- >2.1.1 > > >From ae12c3a9f0e782ff56bd7abf79c9ac25fcbf7015 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Sun, 10 Aug 2014 18:26:14 -0700 >Subject: [PATCH 43/45] regedit: handle pgup/pgdn/home/end keys on lists > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 3b80f256bac0842f4470f9d5361426d7cff88ea9) >--- > source3/utils/regedit.c | 28 ++++++++++++++++++ > source3/utils/regedit_list.c | 67 ++++++++++++++++++++++++++++++++++++++++++-- > source3/utils/regedit_list.h | 6 +++- > 3 files changed, 97 insertions(+), 4 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 34a63d7..9cb4fca 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -378,6 +378,22 @@ static void handle_tree_input(struct regedit *regedit, int c) > tree_view_driver(regedit->keys, ML_CURSOR_UP); > load_values(regedit); > break; >+ case KEY_NPAGE: >+ tree_view_driver(regedit->keys, ML_CURSOR_PGDN); >+ load_values(regedit); >+ break; >+ case KEY_PPAGE: >+ tree_view_driver(regedit->keys, ML_CURSOR_PGUP); >+ load_values(regedit); >+ break; >+ case KEY_HOME: >+ tree_view_driver(regedit->keys, ML_CURSOR_HOME); >+ load_values(regedit); >+ break; >+ case KEY_END: >+ tree_view_driver(regedit->keys, ML_CURSOR_END); >+ load_values(regedit); >+ break; > case '\n': > case KEY_ENTER: > case KEY_RIGHT: >@@ -476,6 +492,18 @@ static void handle_value_input(struct regedit *regedit, int c) > case KEY_UP: > value_list_driver(regedit->vl, ML_CURSOR_UP); > break; >+ case KEY_NPAGE: >+ value_list_driver(regedit->vl, ML_CURSOR_PGDN); >+ break; >+ case KEY_PPAGE: >+ value_list_driver(regedit->vl, ML_CURSOR_PGUP); >+ break; >+ case KEY_HOME: >+ value_list_driver(regedit->vl, ML_CURSOR_HOME); >+ break; >+ case KEY_END: >+ value_list_driver(regedit->vl, ML_CURSOR_END); >+ break; > case 'b': > case 'B': > binmode = true; >diff --git a/source3/utils/regedit_list.c b/source3/utils/regedit_list.c >index ac4e240..c2b3705 100644 >--- a/source3/utils/regedit_list.c >+++ b/source3/utils/regedit_list.c >@@ -405,21 +405,33 @@ WERROR multilist_set_data(struct multilist *list, const void *data) > return WERR_OK; > } > >-static void fix_start_row(struct multilist *list) >+static int get_window_height(struct multilist *list) > { > int height; > >- /* adjust start_row so that the cursor appears on the screen */ >- > height = list->window_height; > if (list->cb->get_column_header) { > height--; > } >+ >+ return height; >+} >+ >+static void fix_start_row(struct multilist *list) >+{ >+ int height; >+ >+ /* adjust start_row so that the cursor appears on the screen */ >+ >+ height = get_window_height(list); > if (list->cursor_row < list->start_row) { > list->start_row = list->cursor_row; > } else if (list->cursor_row >= list->start_row + height) { > list->start_row = list->cursor_row - height + 1; > } >+ if (list->nrows > height && list->nrows - list->start_row < height) { >+ list->start_row = list->nrows - height; >+ } > } > > WERROR multilist_set_window(struct multilist *list, WINDOW *window) >@@ -457,6 +469,10 @@ void multilist_refresh(struct multilist *list) > { > int window_start_row, height; > >+ if (list->nrows == 0) { >+ return; >+ } >+ > /* copy from pad, starting at start_row, to the window, accounting > for the column header (if present). */ > height = MIN(list->window_height, list->nrows); >@@ -474,6 +490,7 @@ void multilist_refresh(struct multilist *list) > > void multilist_driver(struct multilist *list, int c) > { >+ unsigned page; > const void *tmp; > > if (list->nrows == 0) { >@@ -497,6 +514,50 @@ void multilist_driver(struct multilist *list, int c) > list->cursor_row++; > tmp = data_get_next_row(list, list->current_row); > break; >+ case ML_CURSOR_PGUP: >+ if (list->cursor_row == 0) { >+ return; >+ } >+ unhighlight_current_row(list); >+ page = get_window_height(list); >+ if (page > list->cursor_row) { >+ list->cursor_row = 0; >+ } else { >+ list->cursor_row -= page; >+ list->start_row -= page; >+ } >+ tmp = data_get_row_n(list, list->cursor_row); >+ break; >+ case ML_CURSOR_PGDN: >+ if (list->cursor_row == list->nrows - 1) { >+ return; >+ } >+ unhighlight_current_row(list); >+ page = get_window_height(list); >+ if (page > list->nrows - list->cursor_row - 1) { >+ list->cursor_row = list->nrows - 1; >+ } else { >+ list->cursor_row += page; >+ list->start_row += page; >+ } >+ tmp = data_get_row_n(list, list->cursor_row); >+ break; >+ case ML_CURSOR_HOME: >+ if (list->cursor_row == 0) { >+ return; >+ } >+ unhighlight_current_row(list); >+ list->cursor_row = 0; >+ tmp = data_get_row_n(list, list->cursor_row); >+ break; >+ case ML_CURSOR_END: >+ if (list->cursor_row == list->nrows - 1) { >+ return; >+ } >+ unhighlight_current_row(list); >+ list->cursor_row = list->nrows - 1; >+ tmp = data_get_row_n(list, list->cursor_row); >+ break; > } > > SMB_ASSERT(tmp); >diff --git a/source3/utils/regedit_list.h b/source3/utils/regedit_list.h >index 4b1840a..abd6ffd 100644 >--- a/source3/utils/regedit_list.h >+++ b/source3/utils/regedit_list.h >@@ -69,7 +69,11 @@ void multilist_refresh(struct multilist *list); > > enum { > ML_CURSOR_UP, >- ML_CURSOR_DOWN >+ ML_CURSOR_DOWN, >+ ML_CURSOR_PGUP, >+ ML_CURSOR_PGDN, >+ ML_CURSOR_HOME, >+ ML_CURSOR_END > }; > void multilist_driver(struct multilist *list, int c); > const void *multilist_get_current_row(struct multilist *list); >-- >2.1.1 > > >From 43060387ad1459f9ba616eb9166d48cc29509004 Mon Sep 17 00:00:00 2001 >From: Chris Davis <cd.rattan@gmail.com> >Date: Thu, 7 Aug 2014 06:17:28 -0700 >Subject: [PATCH 44/45] regedit: print error msg if opening registry fails > >Signed-off-by: Chris Davis <cd.rattan@gmail.com> >Reviewed-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >(cherry picked from commit 61cc5185e5ccf1bb6d1201063ac3a62e3b7fcfbb) >--- > source3/utils/regedit.c | 2 ++ > 1 file changed, 2 insertions(+) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index 9cb4fca..fe2caf6 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -796,6 +796,8 @@ int main(int argc, const char **argv) > > rv = reg_open_samba3(frame, &ctx); > if (!W_ERROR_IS_OK(rv)) { >+ fprintf(stderr, "Unable to open registry: %s\n", >+ win_errstr(rv)); > TALLOC_FREE(frame); > > return 1; >-- >2.1.1 > > >From 168f63bdca19e7d7a0d8e1ad5474f90f491d9c50 Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Wed, 1 Oct 2014 11:36:36 +0200 >Subject: [PATCH 45/45] regedit: remove an old comment > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Andreas Schneider <asn@samba.org> > >Autobuild-User(master): Michael Adam <obnox@samba.org> >Autobuild-Date(master): Wed Oct 1 16:55:05 CEST 2014 on sn-devel-104 > >(cherry picked from commit fa9630e368df2446c5893b2fe51bada7a38760aa) >--- > source3/utils/regedit.c | 2 -- > 1 file changed, 2 deletions(-) > >diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c >index fe2caf6..bff23ec 100644 >--- a/source3/utils/regedit.c >+++ b/source3/utils/regedit.c >@@ -792,8 +792,6 @@ int main(int argc, const char **argv) > exit(1); > } > >- /* some simple tests */ >- > rv = reg_open_samba3(frame, &ctx); > if (!W_ERROR_IS_OK(rv)) { > fprintf(stderr, "Unable to open registry: %s\n", >-- >2.1.1 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Flags:
obnox
:
review+
Actions:
View
Attachments on
bug 10859
: 10331