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 tree_node
*node
)
202 SMB_ASSERT(node
->parent
!= NULL
);
203 SMB_ASSERT(node
->name
!= NULL
);
204 TALLOC_FREE(node
->key
);
205 return reg_open_key(node
->parent
, node
->parent
->key
, node
->name
,
209 bool tree_node_has_children(struct tree_node
*node
)
211 if (node
->child_head
) {
215 return get_num_subkeys(node
) > 0;
218 static int node_cmp(struct tree_node
**a
, struct tree_node
**b
)
220 return strcmp((*a
)->name
, (*b
)->name
);
223 void tree_node_insert_sorted(struct tree_node
*list
, struct tree_node
*node
)
225 list
= tree_node_first(list
);
227 if (node_cmp(&list
, &node
) >= 0) {
228 tree_node_append(node
, list
);
230 list
->parent
->child_head
= node
;
235 while (list
->next
&& node_cmp(&list
->next
, &node
) < 0) {
239 tree_node_append(list
, node
);
242 WERROR
tree_node_load_children(struct tree_node
*node
)
244 struct registry_key
*key
;
245 const char *key_name
, *klass
;
247 uint32_t i
, nsubkeys
, count
;
249 struct tree_node
*prev
, **array
;
251 /* does this node already have it's children loaded? */
252 if (node
->child_head
)
255 nsubkeys
= get_num_subkeys(node
);
259 array
= talloc_zero_array(node
, struct tree_node
*, nsubkeys
);
264 for (count
= 0, i
= 0; i
< nsubkeys
; ++i
) {
265 rv
= reg_key_get_subkey_by_index(node
, node
->key
, i
,
268 if (!W_ERROR_IS_OK(rv
)) {
272 rv
= reg_open_key(node
, node
->key
, key_name
, &key
);
273 if (!W_ERROR_IS_OK(rv
)) {
277 array
[count
] = tree_node_new(array
, node
, key_name
, key
);
278 if (array
[count
] == NULL
) {
286 TYPESAFE_QSORT(array
, count
, node_cmp
);
288 for (i
= 1, prev
= array
[0]; i
< count
; ++i
) {
289 talloc_steal(node
, array
[i
]);
290 tree_node_append(prev
, array
[i
]);
293 node
->child_head
= talloc_steal(node
, array
[0]);
304 void tree_view_clear(struct tree_view
*view
)
306 multilist_set_data(view
->list
, NULL
);
309 WERROR
tree_view_set_root(struct tree_view
*view
, struct tree_node
*root
)
311 multilist_set_data(view
->list
, NULL
);
312 talloc_free(view
->root
);
314 return tree_view_update(view
, root
->child_head
);
317 WERROR
tree_view_set_path(struct tree_view
*view
, const char **path
)
319 struct tree_node
*top
, *node
;
322 top
= view
->root
->child_head
;
324 for (node
= top
; node
!= NULL
; node
= node
->next
) {
325 if (strcmp(*path
, node
->name
) == 0) {
326 if (path
[1] && tree_node_has_children(node
)) {
327 rv
= tree_node_load_children(node
);
328 if (!W_ERROR_IS_OK(rv
)) {
331 SMB_ASSERT(node
->child_head
);
332 top
= node
->child_head
;
335 tree_view_update(view
, top
);
336 tree_view_set_current_node(view
, node
);
347 WERROR
tree_view_update(struct tree_view
*view
, struct tree_node
*list
)
351 rv
= multilist_set_data(view
->list
, list
);
352 if (W_ERROR_IS_OK(rv
)) {
353 multilist_refresh(view
->list
);
359 /* is this node in the current level? */
360 bool tree_view_is_node_visible(struct tree_view
*view
, struct tree_node
*node
)
362 const struct tree_node
*first
;
364 first
= multilist_get_data(view
->list
);
366 return first
&& first
->parent
== node
->parent
;
369 void tree_view_set_current_node(struct tree_view
*view
, struct tree_node
*node
)
371 multilist_set_current_row(view
->list
, node
);
374 struct tree_node
*tree_view_get_current_node(struct tree_view
*view
)
376 const void *row
= multilist_get_current_row(view
->list
);
377 return talloc_get_type_abort(row
, struct tree_node
);
380 void tree_view_driver(struct tree_view
*view
, int c
)
382 multilist_driver(view
->list
, c
);
385 void tree_view_set_selected(struct tree_view
*view
, bool select
)
387 attr_t attr
= A_NORMAL
;
392 mvwchgat(view
->window
, 0, HEADING_X
, 3, attr
, 0, NULL
);
395 void tree_view_show(struct tree_view
*view
)
397 multilist_refresh(view
->list
);
398 touchwin(view
->window
);
399 wnoutrefresh(view
->window
);
400 wnoutrefresh(view
->sub
);
403 static int tree_view_free(struct tree_view
*view
)
406 del_panel(view
->panel
);
412 delwin(view
->window
);
418 static const char *tv_get_column_header(const void *data
, unsigned col
)
420 SMB_ASSERT(col
== 0);
424 static const void *tv_get_first_row(const void *data
)
430 return talloc_get_type_abort(data
, struct tree_node
);
433 static const void *tv_get_next_row(const void *data
, const void *row
)
435 const struct tree_node
*node
;
436 SMB_ASSERT(row
!= NULL
);
437 node
= talloc_get_type_abort(row
, struct tree_node
);
441 static const void *tv_get_prev_row(const void *data
, const void *row
)
443 const struct tree_node
*node
;
444 SMB_ASSERT(row
!= NULL
);
445 node
= talloc_get_type_abort(row
, struct tree_node
);
446 return node
->previous
;
449 static const char *tv_get_item_prefix(const void *row
, unsigned col
)
451 struct tree_node
*node
;
453 SMB_ASSERT(col
== 0);
454 SMB_ASSERT(row
!= NULL
);
455 node
= talloc_get_type_abort(row
, struct tree_node
);
456 if (tree_node_has_children(node
)) {
462 static const char *tv_get_item_label(const void *row
, unsigned col
)
464 const struct tree_node
*node
;
465 SMB_ASSERT(col
== 0);
466 SMB_ASSERT(row
!= NULL
);
467 node
= talloc_get_type_abort(row
, struct tree_node
);
471 static struct multilist_accessors tv_accessors
= {
472 .get_column_header
= tv_get_column_header
,
473 .get_first_row
= tv_get_first_row
,
474 .get_next_row
= tv_get_next_row
,
475 .get_prev_row
= tv_get_prev_row
,
476 .get_item_prefix
= tv_get_item_prefix
,
477 .get_item_label
= tv_get_item_label
480 struct tree_view
*tree_view_new(TALLOC_CTX
*ctx
, struct tree_node
*root
,
481 int nlines
, int ncols
, int begin_y
,
484 struct tree_view
*view
;
486 view
= talloc_zero(ctx
, struct tree_view
);
491 talloc_set_destructor(view
, tree_view_free
);
493 view
->window
= newwin(nlines
, ncols
, begin_y
, begin_x
);
494 if (view
->window
== NULL
) {
497 view
->sub
= subwin(view
->window
, nlines
- 2, ncols
- 2,
498 begin_y
+ 1, begin_x
+ 1);
499 if (view
->sub
== NULL
) {
502 box(view
->window
, 0, 0);
503 mvwprintw(view
->window
, 0, HEADING_X
, "Key");
505 view
->panel
= new_panel(view
->window
);
506 if (view
->panel
== NULL
) {
511 view
->list
= multilist_new(view
, view
->sub
, &tv_accessors
, 1);
512 if (view
->list
== NULL
) {
515 tree_view_update(view
, root
->child_head
);
525 void tree_view_resize(struct tree_view
*view
, int nlines
, int ncols
,
526 int begin_y
, int begin_x
)
530 nwin
= newwin(nlines
, ncols
, begin_y
, begin_x
);
534 nsub
= subwin(nwin
, nlines
- 2, ncols
- 2, begin_y
+ 1, begin_x
+ 1);
539 replace_panel(view
->panel
, nwin
);
541 delwin(view
->window
);
544 box(view
->window
, 0, 0);
545 mvwprintw(view
->window
, 0, HEADING_X
, "Key");
546 multilist_set_window(view
->list
, view
->sub
);
547 tree_view_show(view
);
550 const char **tree_node_get_path(TALLOC_CTX
*ctx
, struct tree_node
*node
)
553 size_t nitems
, index
;
556 for (nitems
= 0, p
= node
; !tree_node_is_root(p
); p
= p
->parent
) {
560 array
= talloc_zero_array(ctx
, const char *, nitems
+ 1);
565 for (index
= nitems
- 1, p
= node
;
566 !tree_node_is_root(p
);
567 p
= p
->parent
, --index
) {
568 array
[index
] = talloc_strdup(array
, p
->name
);
569 if (array
[index
] == NULL
) {
570 talloc_free(discard_const(array
));
578 /* print the path of node to label */
579 size_t tree_node_print_path(WINDOW
*label
, struct tree_node
*node
)
591 if (tree_node_is_top_level(node
))
594 frame
= talloc_stackframe();
595 path
= tree_node_get_path(frame
, node
->parent
);
598 len
+= strlen(*path
) + 1;
599 wprintw(label
, "%s/", *path
);