subunit: report [X/Y at Zs] instead of [X/Y in Zs]
[Samba.git] / source3 / utils / regedit_valuelist.c
blobf12a81ebd27cccc4bab79903c4d1df0f4a23c45b
1 /*
2 * Samba Unix/Linux SMB client library
3 * Registry Editor
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 "includes.h"
21 #include "regedit.h"
22 #include "regedit_valuelist.h"
23 #include "regedit_list.h"
24 #include "lib/registry/registry.h"
26 #define HEADING_X 3
28 static int value_list_free(struct value_list *vl)
30 if (vl->panel) {
31 del_panel(vl->panel);
33 if (vl->sub) {
34 delwin(vl->sub);
36 if (vl->window) {
37 delwin(vl->window);
40 return 0;
43 static const char *vl_get_column_header(const void *data, unsigned col)
45 switch (col) {
46 case 0:
47 return "Name";
48 case 1:
49 return "Type";
50 case 2:
51 return "Data";
54 return "???";
57 static const void *vl_get_first_row(const void *data)
59 const struct value_list *vl;
61 if (data) {
62 vl = talloc_get_type_abort(data, struct value_list);
63 if (vl->nvalues) {
64 return &vl->values[0];
68 return NULL;
71 static const void *vl_get_next_row(const void *data, const void *row)
73 const struct value_list *vl;
74 const struct value_item *value = row;
76 SMB_ASSERT(data != NULL);
77 SMB_ASSERT(value != NULL);
78 vl = talloc_get_type_abort(data, struct value_list);
79 if (value == &vl->values[vl->nvalues - 1]) {
80 return NULL;
83 return value + 1;
86 static const void *vl_get_prev_row(const void *data, const void *row)
88 const struct value_list *vl;
89 const struct value_item *value = row;
91 SMB_ASSERT(data != NULL);
92 SMB_ASSERT(value != NULL);
93 vl = talloc_get_type_abort(data, struct value_list);
94 if (value == &vl->values[0]) {
95 return NULL;
98 return value - 1;
101 static const char *vl_get_item_label(const void *row, unsigned col)
103 const struct value_item *value = row;
105 SMB_ASSERT(value != NULL);
106 SMB_ASSERT(value->value_name != NULL);
107 switch (col) {
108 case 0:
109 return value->value_name;
110 case 1:
111 return str_regtype(value->type);
112 case 2:
113 if (value->value) {
114 return value->value;
116 return "";
119 return "???";
122 static struct multilist_accessors vl_accessors = {
123 .get_column_header = vl_get_column_header,
124 .get_first_row = vl_get_first_row,
125 .get_next_row = vl_get_next_row,
126 .get_prev_row = vl_get_prev_row,
127 .get_item_label = vl_get_item_label
130 struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols,
131 int begin_y, int begin_x)
133 struct value_list *vl;
135 vl = talloc_zero(ctx, struct value_list);
136 if (vl == NULL) {
137 return NULL;
140 talloc_set_destructor(vl, value_list_free);
142 vl->window = newwin(nlines, ncols, begin_y, begin_x);
143 if (vl->window == NULL) {
144 goto fail;
146 vl->sub = subwin(vl->window, nlines - 2, ncols - 2,
147 begin_y + 1, begin_x + 1);
148 if (vl->sub == NULL) {
149 goto fail;
151 box(vl->window, 0, 0);
152 mvwprintw(vl->window, 0, HEADING_X, "Value");
154 vl->panel = new_panel(vl->window);
155 if (vl->panel == NULL) {
156 goto fail;
159 vl->list = multilist_new(vl, vl->sub, &vl_accessors, 3);
160 if (vl->list == NULL) {
161 goto fail;
164 return vl;
166 fail:
167 talloc_free(vl);
169 return NULL;
172 void value_list_set_selected(struct value_list *vl, bool select)
174 attr_t attr = A_NORMAL;
176 if (select) {
177 attr = A_REVERSE;
179 mvwchgat(vl->window, 0, HEADING_X, 5, attr, 0, NULL);
182 void value_list_resize(struct value_list *vl, int nlines, int ncols,
183 int begin_y, int begin_x)
185 WINDOW *nwin, *nsub;
187 nwin = newwin(nlines, ncols, begin_y, begin_x);
188 if (nwin == NULL) {
189 return;
191 nsub = subwin(nwin, nlines - 2, ncols - 2, begin_y + 1, begin_x + 1);
192 if (nsub == NULL) {
193 delwin(nwin);
194 return;
196 replace_panel(vl->panel, nwin);
197 delwin(vl->sub);
198 delwin(vl->window);
199 vl->window = nwin;
200 vl->sub = nsub;
201 box(vl->window, 0, 0);
202 mvwprintw(vl->window, 0, HEADING_X, "Value");
203 multilist_set_window(vl->list, vl->sub);
204 value_list_show(vl);
207 static uint32_t get_num_values(TALLOC_CTX *ctx, const struct registry_key *key)
209 const char *classname;
210 uint32_t num_subkeys;
211 uint32_t num_values;
212 NTTIME last_change_time;
213 uint32_t max_subkeynamelen;
214 uint32_t max_valnamelen;
215 uint32_t max_valbufsize;
216 WERROR rv;
218 rv = reg_key_get_info(ctx, key, &classname, &num_subkeys,
219 &num_values, &last_change_time,
220 &max_subkeynamelen, &max_valnamelen,
221 &max_valbufsize);
223 if (W_ERROR_IS_OK(rv)) {
224 return num_values;
227 return 0;
230 void value_list_show(struct value_list *vl)
232 multilist_refresh(vl->list);
233 touchwin(vl->window);
234 wnoutrefresh(vl->window);
235 wnoutrefresh(vl->sub);
238 static bool string_is_printable(const char *s)
240 const char *p;
242 for (p = s; *p; ++p) {
243 if (!isprint(*p)) {
244 return false;
248 return true;
251 static WERROR append_data_summary(TALLOC_CTX *ctx, struct value_item *vitem)
253 char *tmp = NULL;
255 /* This is adapted from print_registry_value() in net_registry_util.c */
257 switch(vitem->type) {
258 case REG_DWORD: {
259 uint32_t v = 0;
260 if (vitem->data.length >= 4) {
261 v = IVAL(vitem->data.data, 0);
263 tmp = talloc_asprintf(ctx, "0x%08x (%u)", v, v);
264 break;
266 case REG_SZ:
267 case REG_EXPAND_SZ: {
268 const char *s;
270 if (!pull_reg_sz(ctx, &vitem->data, &s)) {
271 break;
273 vitem->unprintable = !string_is_printable(s);
274 if (vitem->unprintable) {
275 tmp = talloc_asprintf(ctx, "(unprintable)");
276 } else {
277 tmp = talloc_asprintf(ctx, "%s", s);
279 break;
281 case REG_MULTI_SZ: {
282 size_t i, len;
283 const char **a;
284 const char *val;
286 if (!pull_reg_multi_sz(ctx, &vitem->data, &a)) {
287 break;
289 for (len = 0; a[len] != NULL; ++len) {
291 tmp = talloc_asprintf(ctx, "(%u) ", (unsigned)len);
292 if (tmp == NULL) {
293 return WERR_NOMEM;
295 for (i = 0; i < len; ++i) {
296 if (!string_is_printable(a[i])) {
297 val = "(unprintable)";
298 vitem->unprintable = true;
299 } else {
300 val = a[i];
302 if (i == len - 1) {
303 tmp = talloc_asprintf_append(tmp,
304 "[%u]=\"%s\"",
305 (unsigned)i, val);
306 } else {
307 tmp = talloc_asprintf_append(tmp,
308 "[%u]=\"%s\", ",
309 (unsigned)i, val);
311 if (tmp == NULL) {
312 return WERR_NOMEM;
315 break;
317 case REG_BINARY:
318 tmp = talloc_asprintf(ctx, "(%d bytes)",
319 (int)vitem->data.length);
320 break;
321 default:
322 tmp = talloc_asprintf(ctx, "(unknown)");
323 break;
326 if (tmp == NULL) {
327 return WERR_NOMEM;
330 vitem->value = tmp;
332 return WERR_OK;
335 static int vitem_cmp(struct value_item *a, struct value_item *b)
337 return strcmp(a->value_name, b->value_name);
340 /* load only the value names into memory to enable searching */
341 WERROR value_list_load_quick(struct value_list *vl, struct registry_key *key)
343 uint32_t nvalues;
344 uint32_t idx;
345 struct value_item *vitem, *new_items;
346 WERROR rv;
348 multilist_set_data(vl->list, NULL);
349 vl->nvalues = 0;
350 TALLOC_FREE(vl->values);
352 nvalues = get_num_values(vl, key);
353 if (nvalues == 0) {
354 return WERR_OK;
357 new_items = talloc_zero_array(vl, struct value_item, nvalues);
358 if (new_items == NULL) {
359 return WERR_NOMEM;
362 for (idx = 0; idx < nvalues; ++idx) {
363 vitem = &new_items[idx];
364 rv = reg_key_get_value_by_index(new_items, key, idx,
365 &vitem->value_name,
366 &vitem->type,
367 &vitem->data);
368 if (!W_ERROR_IS_OK(rv)) {
369 talloc_free(new_items);
370 return rv;
374 TYPESAFE_QSORT(new_items, nvalues, vitem_cmp);
375 vl->nvalues = nvalues;
376 vl->values = new_items;
378 return rv;
381 /* sync up the UI with the list */
382 WERROR value_list_sync(struct value_list *vl)
384 uint32_t idx;
385 WERROR rv;
387 for (idx = 0; idx < vl->nvalues; ++idx) {
388 rv = append_data_summary(vl->values, &vl->values[idx]);
389 if (!W_ERROR_IS_OK(rv)) {
390 return rv;
394 rv = multilist_set_data(vl->list, vl);
395 if (W_ERROR_IS_OK(rv)) {
396 multilist_refresh(vl->list);
399 return rv;
402 WERROR value_list_load(struct value_list *vl, struct registry_key *key)
404 WERROR rv;
406 rv = value_list_load_quick(vl, key);
407 if (!W_ERROR_IS_OK(rv)) {
408 return rv;
411 rv = value_list_sync(vl);
413 return rv;
416 struct value_item *value_list_find_next_item(struct value_list *vl,
417 struct value_item *vitem,
418 const char *s,
419 regedit_search_match_fn_t match)
421 struct value_item *end;
423 if (!vl->values) {
424 return NULL;
427 if (vitem) {
428 ++vitem;
429 } else {
430 vitem = &vl->values[0];
433 for (end = &vl->values[vl->nvalues]; vitem < end; ++vitem) {
434 if (match(vitem->value_name, s)) {
435 return vitem;
439 return NULL;
442 struct value_item *value_list_find_prev_item(struct value_list *vl,
443 struct value_item *vitem,
444 const char *s,
445 regedit_search_match_fn_t match)
447 struct value_item *end;
449 if (!vl->values) {
450 return NULL;
453 if (vitem) {
454 --vitem;
455 } else {
456 vitem = &vl->values[vl->nvalues - 1];
459 for (end = &vl->values[-1]; vitem > end; --vitem) {
460 if (match(vitem->value_name, s)) {
461 return vitem;
465 return NULL;
468 struct value_item *value_list_get_current_item(struct value_list *vl)
470 return discard_const_p(struct value_item,
471 multilist_get_current_row(vl->list));
474 void value_list_set_current_item_by_name(struct value_list *vl,
475 const char *name)
477 size_t i;
479 for (i = 0; i < vl->nvalues; ++i) {
480 if (strequal(vl->values[i].value_name, name)) {
481 multilist_set_current_row(vl->list, &vl->values[i]);
482 return;
487 void value_list_set_current_item(struct value_list *vl,
488 const struct value_item *item)
490 multilist_set_current_row(vl->list, item);
493 void value_list_driver(struct value_list *vl, int c)
495 multilist_driver(vl->list, c);