X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=ui%2Fncurses%2Fnc-widgets.c;h=afd56d71cf90b79d83ee8a07fd4bdfc466e1b508;hp=7e03e573d943a81d84ce45c3ba56a2729c8029ed;hb=07f6db7fc29a93fae3213af18371cccb17e0276a;hpb=5acb43464206348b7cced9508852fdd2989aea58 diff --git a/ui/ncurses/nc-widgets.c b/ui/ncurses/nc-widgets.c index 7e03e57..afd56d7 100644 --- a/ui/ncurses/nc-widgets.c +++ b/ui/ncurses/nc-widgets.c @@ -44,8 +44,10 @@ # error "Curses form.h not found." #endif -#include +#include #include +#include +#include #include #include @@ -53,6 +55,7 @@ #include #include #include +#include #include "nc-cui.h" #include "nc-widgets.h" @@ -82,7 +85,9 @@ struct nc_widgetset { FIELD *cur_field; /* custom validators */ - FIELDTYPE *ipv4_multi_type; + FIELDTYPE *ip_multi_type; + FIELDTYPE *ip_type; + FIELDTYPE *url_type; }; struct nc_widget { @@ -162,21 +167,6 @@ static bool key_is_select(int key) return key == ' ' || key == '\r' || key == '\n' || key == KEY_ENTER; } -static bool key_is_minus(int key) -{ - return key == 055; -} - -static bool key_is_left(int key) -{ - return key == KEY_LEFT; -} - -static bool key_is_right(int key) -{ - return key == KEY_RIGHT; -} - static bool process_key_nop(struct nc_widget *widget __attribute__((unused)), FORM *form __attribute((unused)), int key __attribute__((unused))) @@ -352,6 +342,14 @@ static bool textbox_process_key( case KEY_DC: form_driver(form, REQ_DEL_CHAR); break; + case '\t': + case KEY_BTAB: + case KEY_UP: + case KEY_DOWN: + case KEY_PPAGE: + case KEY_NPAGE: + /* Don't catch navigational keys */ + return false; default: form_driver(form, key); break; @@ -367,8 +365,8 @@ static int textbox_destructor(void *ptr) return 0; } -struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set, - int y, int x, int len, char *str) +struct nc_widget_textbox *widget_new_textbox_hidden(struct nc_widgetset *set, + int y, int x, int len, char *str, bool hide_input) { struct nc_widget_textbox *textbox; FIELD *f; @@ -385,6 +383,8 @@ struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set, textbox->widget.unfocussed_attr = A_UNDERLINE; field_opts_off(f, O_STATIC | O_WRAP | O_BLANK); + if (hide_input) + field_opts_off(f, O_PUBLIC); set_field_buffer(f, 0, str); set_field_back(f, textbox->widget.unfocussed_attr); set_field_userptr(f, &textbox->widget); @@ -395,6 +395,12 @@ struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set, return textbox; } +struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set, + int y, int x, int len, char *str) +{ + return widget_new_textbox_hidden(set, y, x, len, str, false); +} + void widget_textbox_set_fixed_size(struct nc_widget_textbox *textbox) { field_opts_on(textbox->widget.field, O_STATIC); @@ -406,54 +412,102 @@ void widget_textbox_set_validator_integer(struct nc_widget_textbox *textbox, set_field_type(textbox->widget.field, TYPE_INTEGER, 1, min, max); } -void widget_textbox_set_validator_ipv4(struct nc_widget_textbox *textbox) +static bool check_url_field(FIELD *field, + const void *arg __attribute__((unused))) { - set_field_type(textbox->widget.field, TYPE_IPV4); + return is_url(field_buffer(field, 0)); } -static bool check_ipv4_multi_char(int c, +void widget_textbox_set_validator_url(struct nc_widget_textbox *textbox) +{ + if (!textbox->set->url_type) + textbox->set->url_type = new_fieldtype(check_url_field, NULL); + + set_field_type(textbox->widget.field, textbox->set->url_type); +} + +static bool check_ip_field(FIELD *field, const void *arg __attribute__((unused))) +{ + char *str; + int rc; + + str = strip_string(field_buffer(field, 0)); + + rc = addr_scheme(str); + + return (rc == AF_INET || rc == AF_INET6); +} + + +static bool check_ipv6_multi_char(int c) +{ + return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || + c == ':' || c == ' '; +} + +static bool check_ipv4_multi_char(int c) { return isdigit(c) || c == '.' || c == ' '; } -static bool check_ipv4_multi_field(FIELD *field, +static bool check_ip_multi_field(FIELD *field, const void *arg __attribute__((unused))) { - char *buf = field_buffer(field, 0); - unsigned int ip[4]; - int n, len; - - while (*buf != '\0') { - n = sscanf(buf, "%u.%u.%u.%u%n", - &ip[0], &ip[1], &ip[2], &ip[3], &len); - if (n != 4) - return false; - - if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255) - return false; - - for (buf += len; *buf != '\0'; buf++) { - if (isspace(*buf)) - continue; - else if (isdigit(*buf)) - break; - else - return false; - } + char *buf, *tok, *saveptr; + bool result; + int type; + + /* Use strdup directly since we can't easily reach a talloc parent */ + buf = strdup(strip_string(field_buffer(field, 0))); + if (!buf) + /* We tried */ + return true; + + result = false; + tok = strtok_r(buf, " ", &saveptr); + if (!tok || *tok == '\0') + goto err; + + while (tok) { + type = addr_scheme(tok); + if (!(type == AF_INET || type == AF_INET6)) + goto err; + + tok = strtok_r(NULL, " ", &saveptr); } + result = true; - return true; +err: + free(buf); + return result; } -void widget_textbox_set_validator_ipv4_multi(struct nc_widget_textbox *textbox) +static bool check_ip_multi_char(int c, const void *arg __attribute__((unused))) { - if (!textbox->set->ipv4_multi_type) { - textbox->set->ipv4_multi_type = new_fieldtype( - check_ipv4_multi_field, - check_ipv4_multi_char); + return (check_ipv4_multi_char(c) || check_ipv6_multi_char(c)); +} + +void widget_textbox_set_validator_ip(struct nc_widget_textbox *textbox) +{ + if (!textbox->set->ip_type) { + textbox->set->ip_type = new_fieldtype(check_ip_field, NULL); } - set_field_type(textbox->widget.field, textbox->set->ipv4_multi_type); + set_field_type(textbox->widget.field, textbox->set->ip_type); +} + +/* + * In a perfect world we would use link_fieldtype() but segfaults do not + * enhance the user experience. + */ +void widget_textbox_set_validator_ip_multi(struct nc_widget_textbox *textbox) +{ + if (!textbox->set->ip_multi_type) { + textbox->set->ip_multi_type = new_fieldtype( + check_ip_multi_field, + check_ip_multi_char); + } + set_field_type(textbox->widget.field, textbox->set->ip_multi_type); } static void subset_update_order(struct nc_widget_subset *subset) @@ -481,6 +535,7 @@ static void subset_delete_active(struct nc_widget_subset *subset, int idx) struct nc_widget *widget; size_t rem; int i, val; + uint32_t opts; /* Shift field focus to nearest active option or next visible field */ if (subset->n_active > 1) { @@ -492,8 +547,11 @@ static void subset_delete_active(struct nc_widget_subset *subset, int idx) } else { for (i = 0; i < set->n_fields; i++) if (field_visible(set->fields[i])) { - set->cur_field = set->fields[i]; - break; + opts = field_opts(set->fields[i]); + if ((opts & O_ACTIVE) == O_ACTIVE) { + set->cur_field = set->fields[i]; + break; + } } } @@ -522,7 +580,7 @@ static bool subset_process_key(struct nc_widget *w, FORM *form, int key) int i, val, opt_idx = -1; FIELD *field; - if (!key_is_minus(key) && !key_is_left(key) && !key_is_right(key)) + if (key != '-' && key != '+' && key != KEY_DC && key != KEY_BACKSPACE) return false; field = current_field(form); @@ -538,10 +596,10 @@ static bool subset_process_key(struct nc_widget *w, FORM *form, int key) if (opt_idx < 0) return false; - if (key_is_minus(key)) + if (key == KEY_DC || key == KEY_BACKSPACE) subset_delete_active(subset, opt_idx); - if (key_is_left(key)){ + if (key == '-') { if (opt_idx == 0) return true; @@ -550,7 +608,7 @@ static bool subset_process_key(struct nc_widget *w, FORM *form, int key) subset->active[opt_idx - 1] = val; } - if (key_is_right(key)){ + if (key == '+') { if (opt_idx >= subset->n_active - 1) return true; @@ -1121,6 +1179,12 @@ bool widgetset_process_key(struct nc_widgetset *set, int key) field = current_field(set->form); assert(field); + widget = field_userptr(field); + + if (widget->process_key) + if (widget->process_key(widget, set->form, key)) + return true; + tab = false; /* handle field change events */ @@ -1143,9 +1207,14 @@ bool widgetset_process_key(struct nc_widgetset *set, int key) case KEY_NPAGE: req = REQ_SLAST_FIELD; break; + case KEY_LEFT: + req = REQ_LEFT_FIELD; + break; + case KEY_RIGHT: + req = REQ_RIGHT_FIELD; + break; } - widget = field_userptr(field); if (req) { widget_focus_change(widget, field, false); form_driver(set->form, req); @@ -1170,18 +1239,19 @@ bool widgetset_process_key(struct nc_widgetset *set, int key) return true; } - if (!widget->process_key) - return false; - - return widget->process_key(widget, set->form, key); + return false; } static int widgetset_destructor(void *ptr) { struct nc_widgetset *set = ptr; free_form(set->form); - if (set->ipv4_multi_type) - free_fieldtype(set->ipv4_multi_type); + if (set->ip_type) + free_fieldtype(set->ip_type); + if (set->ip_multi_type) + free_fieldtype(set->ip_multi_type); + if (set->url_type) + free_fieldtype(set->url_type); return 0; } @@ -1224,10 +1294,8 @@ void widgetset_post(struct nc_widgetset *set) post_form(set->form); form_driver(set->form, REQ_END_FIELD); - if (set->cur_field) { + if (set->cur_field) set_current_field(set->form, set->cur_field); - field = set->cur_field; - } field = current_field(set->form); widget = field_userptr(field);