2 * Samba Unix/Linux SMB client library
4 * Copyright (C) Christopher Davis 2012
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "regedit_treeview.h"
21 #include "regedit_list.h"
22 #include "lib/registry/registry.h"
26 static int tree_node_free(struct tree_node
*node
)
28 DEBUG(9, ("tree_node_free('%s', %p)\n", node
->name
, node
));
32 struct tree_node
*tree_node_new(TALLOC_CTX
*ctx
, struct tree_node
*parent
,
33 const char *name
, struct registry_key
*key
)
35 struct tree_node
*node
;
37 node
= talloc_zero(ctx
, struct tree_node
);
41 talloc_set_destructor(node
, tree_node_free
);
42 DEBUG(9, ("tree_node_new('%s', %p)\n", name
, node
));
44 node
->name
= talloc_strdup(node
, name
);
51 node
->key
= talloc_steal(node
, key
);
55 /* Check if this node is the first descendant of parent. */
56 if (!parent
->child_head
) {
57 parent
->child_head
= node
;
59 node
->parent
= parent
;
65 /* prepare a root node with all available hives as children */
66 struct tree_node
*tree_node_new_root(TALLOC_CTX
*ctx
,
67 struct registry_context
*regctx
)
69 const char *hives
[] = {
73 "HKEY_PERFORMANCE_DATA",
75 "HKEY_CURRENT_CONFIG",
77 "HKEY_PERFORMANCE_TEXT",
78 "HKEY_PERFORMANCE_NLSTEXT",
81 struct tree_node
*root
, *prev
, *node
;
82 struct registry_key
*key
;
86 root
= tree_node_new(ctx
, NULL
, "ROOT", NULL
);
92 for (i
= 0; hives
[i
] != NULL
; ++i
) {
93 rv
= reg_get_predefined_key_by_name(regctx
, hives
[i
], &key
);
94 if (!W_ERROR_IS_OK(rv
)) {
98 node
= tree_node_new(root
, root
, hives
[i
], key
);
103 tree_node_append(prev
, node
);
111 void tree_node_append(struct tree_node
*left
, struct tree_node
*right
)
114 right
->next
= left
->next
;
115 left
->next
->previous
= right
;
118 right
->previous
= left
;
121 void tree_node_append_last(struct tree_node
*list
, struct tree_node
*node
)
123 tree_node_append(tree_node_last(list
), node
);
126 struct tree_node
*tree_node_pop(struct tree_node
**plist
)
128 struct tree_node
*node
;
135 *plist
= node
->previous
;
136 if (*plist
== NULL
) {
139 if (node
->previous
) {
140 node
->previous
->next
= node
->next
;
143 node
->next
->previous
= node
->previous
;
145 if (node
->parent
&& node
->parent
->child_head
== node
) {
146 node
->parent
->child_head
= node
->next
;
149 node
->previous
= NULL
;
154 struct tree_node
*tree_node_first(struct tree_node
*list
)
156 /* Grab the first node in this list from the parent if available. */
158 return list
->parent
->child_head
;
161 while (list
&& list
->previous
) {
162 list
= list
->previous
;
168 struct tree_node
*tree_node_last(struct tree_node
*list
)
170 while (list
&& list
->next
) {
177 static uint32_t get_num_subkeys(struct tree_node
*node
)
179 const char *classname
;
180 uint32_t num_subkeys
;
182 NTTIME last_change_time
;
183 uint32_t max_subkeynamelen
;
184 uint32_t max_valnamelen
;
185 uint32_t max_valbufsize
;
188 rv
= reg_key_get_info(node
, node
->key
, &classname
, &num_subkeys
,
189 &num_values
, &last_change_time
,
190 &max_subkeynamelen
, &max_valnamelen
,
193 if (W_ERROR_IS_OK(rv
)) {
200 WERROR
tree_node_reopen_key(struct registry_context
*ctx
,
201 struct tree_node
*node
)
203 SMB_ASSERT(node
->parent
!= NULL
);
204 SMB_ASSERT(node
->name
!= NULL
);
205 TALLOC_FREE(node
->key
);
207 if (tree_node_is_top_level(node
)) {
209 struct registry_key
*key
;
210 rv
= reg_get_predefined_key_by_name(ctx
, node
->name
, &key
);
211 if (W_ERROR_IS_OK(rv
)) {
212 node
->key
= talloc_steal(node
, key
);
217 return reg_open_key(node
, node
->parent
->key
, node
->name
, &node
->key
);
220 bool tree_node_has_children(struct tree_node
*node
)
222 if (node
->child_head
) {
226 return get_num_subkeys(node
) > 0;
229 static int node_cmp(struct tree_node
**a
, struct tree_node
**b
)
231 return strcmp((*a
)->name
, (*b
)->name
);
234 void tree_node_insert_sorted(struct tree_node
*list
, struct tree_node
*node
)
236 list
= tree_node_first(list
);
238 if (node_cmp(&list
, &node
) >= 0) {
239 tree_node_append(node
, list
);
241 list
->parent
->child_head
= node
;
246 while (list
->next
&& node_cmp(&list
->next
, &node
) < 0) {
250 tree_node_append(list
, node
);
253 WERROR
tree_node_load_children(struct tree_node
*node
)
255 struct registry_key
*key
;
256 const char *key_name
, *klass
;
258 uint32_t i
, nsubkeys
, count
;
260 struct tree_node
*prev
, **array
;
262 /* does this node already have it's children loaded? */
263 if (node
->child_head
)
266 nsubkeys
= get_num_subkeys(node
);
270 array
= talloc_zero_array(node
, struct tree_node
*, nsubkeys
);
275 for (count
= 0, i
= 0; i
< nsubkeys
; ++i
) {
276 rv
= reg_key_get_subkey_by_index(node
, node
->key
, i
,
279 if (!W_ERROR_IS_OK(rv
)) {
283 rv
= reg_open_key(node
, node
->key
, key_name
, &key
);
284 if (!W_ERROR_IS_OK(rv
)) {
288 array
[count
] = tree_node_new(array
, node
, key_name
, key
);
289 if (array
[count
] == NULL
) {
297 TYPESAFE_QSORT(array
, count
, node_cmp
);
299 for (i
= 1, prev
= array
[0]; i
< count
; ++i
) {
300 talloc_steal(node
, array
[i
]);
301 tree_node_append(prev
, array
[i
]);
304 node
->child_head
= talloc_steal(node
, array
[0]);
315 static WERROR
next_depth_first(struct tree_node
**node
)
319 SMB_ASSERT(node
!= NULL
&& *node
!= NULL
);
321 if (tree_node_has_children(*node
)) {
322 /* 1. If the node has children, go to the first one. */
323 rv
= tree_node_load_children(*node
);
324 if (W_ERROR_IS_OK(rv
)) {
325 SMB_ASSERT((*node
)->child_head
!= NULL
);
326 *node
= (*node
)->child_head
;
328 } else if ((*node
)->next
) {
329 /* 2. If there's a node directly after this one, go there */
330 *node
= (*node
)->next
;
332 /* 3. Otherwise, go up the hierarchy to find the next one */
334 *node
= (*node
)->parent
;
335 if (*node
&& (*node
)->next
) {
336 *node
= (*node
)->next
;
345 static WERROR
prev_depth_first(struct tree_node
**node
)
349 SMB_ASSERT(node
!= NULL
&& *node
!= NULL
);
351 if ((*node
)->previous
) {
352 *node
= (*node
)->previous
;
353 while (tree_node_has_children(*node
)) {
354 rv
= tree_node_load_children(*node
);
355 if (W_ERROR_IS_OK(rv
)) {
356 SMB_ASSERT((*node
)->child_head
!= NULL
);
357 *node
= tree_node_last((*node
)->child_head
);
360 } else if (!tree_node_is_top_level(*node
)) {
361 *node
= (*node
)->parent
;
369 bool tree_node_next(struct tree_node
**node
, bool depth
, WERROR
*err
)
378 *err
= next_depth_first(node
);
380 *node
= (*node
)->next
;
383 return *node
!= NULL
&& W_ERROR_IS_OK(*err
);
386 bool tree_node_prev(struct tree_node
**node
, bool depth
, WERROR
*err
)
395 *err
= prev_depth_first(node
);
397 *node
= (*node
)->previous
;
400 return *node
!= NULL
&& W_ERROR_IS_OK(*err
);
403 void tree_view_clear(struct tree_view
*view
)
405 multilist_set_data(view
->list
, NULL
);
408 WERROR
tree_view_set_root(struct tree_view
*view
, struct tree_node
*root
)
410 multilist_set_data(view
->list
, NULL
);
411 talloc_free(view
->root
);
413 return tree_view_update(view
, root
->child_head
);
416 WERROR
tree_view_set_path(struct tree_view
*view
, const char **path
)
418 struct tree_node
*top
, *node
;
421 top
= view
->root
->child_head
;
423 for (node
= top
; node
!= NULL
; node
= node
->next
) {
424 if (strcmp(*path
, node
->name
) == 0) {
425 if (path
[1] && tree_node_has_children(node
)) {
426 rv
= tree_node_load_children(node
);
427 if (!W_ERROR_IS_OK(rv
)) {
430 SMB_ASSERT(node
->child_head
);
431 top
= node
->child_head
;
434 tree_view_update(view
, top
);
435 tree_view_set_current_node(view
, node
);
446 WERROR
tree_view_update(struct tree_view
*view
, struct tree_node
*list
)
450 rv
= multilist_set_data(view
->list
, list
);
451 if (W_ERROR_IS_OK(rv
)) {
452 multilist_refresh(view
->list
);
458 /* is this node in the current level? */
459 bool tree_view_is_node_visible(struct tree_view
*view
, struct tree_node
*node
)
461 const struct tree_node
*first
;
463 first
= multilist_get_data(view
->list
);
465 return first
&& first
->parent
== node
->parent
;
468 void tree_view_set_current_node(struct tree_view
*view
, struct tree_node
*node
)
470 multilist_set_current_row(view
->list
, node
);
473 struct tree_node
*tree_view_get_current_node(struct tree_view
*view
)
475 const void *row
= multilist_get_current_row(view
->list
);
476 return talloc_get_type_abort(row
, struct tree_node
);
479 void tree_view_driver(struct tree_view
*view
, int c
)
481 multilist_driver(view
->list
, c
);
484 void tree_view_set_selected(struct tree_view
*view
, bool reverse
)
486 attr_t attr
= A_NORMAL
;
491 mvwchgat(view
->window
, 0, HEADING_X
, 3, attr
, 0, NULL
);
494 void tree_view_show(struct tree_view
*view
)
496 multilist_refresh(view
->list
);
497 touchwin(view
->window
);
498 wnoutrefresh(view
->window
);
499 wnoutrefresh(view
->sub
);
502 static int tree_view_free(struct tree_view
*view
)
505 del_panel(view
->panel
);
511 delwin(view
->window
);
517 static const char *tv_get_column_header(const void *data
, unsigned col
)
519 SMB_ASSERT(col
== 0);
523 static const void *tv_get_first_row(const void *data
)
529 return talloc_get_type_abort(data
, struct tree_node
);
532 static const void *tv_get_next_row(const void *data
, const void *row
)
534 const struct tree_node
*node
;
535 SMB_ASSERT(row
!= NULL
);
536 node
= talloc_get_type_abort(row
, struct tree_node
);
540 static const void *tv_get_prev_row(const void *data
, const void *row
)
542 const struct tree_node
*node
;
543 SMB_ASSERT(row
!= NULL
);
544 node
= talloc_get_type_abort(row
, struct tree_node
);
545 return node
->previous
;
548 static const char *tv_get_item_prefix(const void *row
, unsigned col
)
550 struct tree_node
*node
;
552 SMB_ASSERT(col
== 0);
553 SMB_ASSERT(row
!= NULL
);
554 node
= talloc_get_type_abort(row
, struct tree_node
);
555 if (tree_node_has_children(node
)) {
561 static const char *tv_get_item_label(const void *row
, unsigned col
)
563 const struct tree_node
*node
;
564 SMB_ASSERT(col
== 0);
565 SMB_ASSERT(row
!= NULL
);
566 node
= talloc_get_type_abort(row
, struct tree_node
);
570 static struct multilist_accessors tv_accessors
= {
571 .get_column_header
= tv_get_column_header
,
572 .get_first_row
= tv_get_first_row
,
573 .get_next_row
= tv_get_next_row
,
574 .get_prev_row
= tv_get_prev_row
,
575 .get_item_prefix
= tv_get_item_prefix
,
576 .get_item_label
= tv_get_item_label
579 struct tree_view
*tree_view_new(TALLOC_CTX
*ctx
, struct tree_node
*root
,
580 int nlines
, int ncols
, int begin_y
,
583 struct tree_view
*view
;
585 view
= talloc_zero(ctx
, struct tree_view
);
590 talloc_set_destructor(view
, tree_view_free
);
592 view
->window
= newwin(nlines
, ncols
, begin_y
, begin_x
);
593 if (view
->window
== NULL
) {
596 view
->sub
= subwin(view
->window
, nlines
- 2, ncols
- 2,
597 begin_y
+ 1, begin_x
+ 1);
598 if (view
->sub
== NULL
) {
601 box(view
->window
, 0, 0);
602 mvwprintw(view
->window
, 0, HEADING_X
, "Key");
604 view
->panel
= new_panel(view
->window
);
605 if (view
->panel
== NULL
) {
610 view
->list
= multilist_new(view
, view
->sub
, &tv_accessors
, 1);
611 if (view
->list
== NULL
) {
614 tree_view_update(view
, root
->child_head
);
624 void tree_view_resize(struct tree_view
*view
, int nlines
, int ncols
,
625 int begin_y
, int begin_x
)
629 nwin
= newwin(nlines
, ncols
, begin_y
, begin_x
);
633 nsub
= subwin(nwin
, nlines
- 2, ncols
- 2, begin_y
+ 1, begin_x
+ 1);
638 replace_panel(view
->panel
, nwin
);
640 delwin(view
->window
);
643 box(view
->window
, 0, 0);
644 mvwprintw(view
->window
, 0, HEADING_X
, "Key");
645 multilist_set_window(view
->list
, view
->sub
);
646 tree_view_show(view
);
649 const char **tree_node_get_path(TALLOC_CTX
*ctx
, struct tree_node
*node
)
655 for (nitems
= 0, p
= node
; !tree_node_is_root(p
); p
= p
->parent
) {
659 array
= talloc_zero_array(ctx
, const char *, nitems
+ 1);
664 for (idx
= nitems
- 1, p
= node
;
665 !tree_node_is_root(p
);
666 p
= p
->parent
, --idx
) {
667 array
[idx
] = talloc_strdup(array
, p
->name
);
668 if (array
[idx
] == NULL
) {
669 talloc_free(discard_const(array
));
677 /* print the path of node to label */
678 size_t tree_node_print_path(WINDOW
*label
, struct tree_node
*node
)
690 if (tree_node_is_top_level(node
))
693 frame
= talloc_stackframe();
694 path
= tree_node_get_path(frame
, node
->parent
);
697 len
+= strlen(*path
) + 1;
698 wprintw(label
, "%s/", *path
);