]> git.ozlabs.org Git - petitboot/blobdiff - ui/ncurses/nc-widgets.c
ui/ncurses/nc-widgets: Add initial textbox validation functions
[petitboot] / ui / ncurses / nc-widgets.c
index 583e5ed82d9169c6762ff986cd2b599e928d103e..2829040b46ba236a7ad01e9e1dd828d0199ac7d9 100644 (file)
@@ -15,9 +15,9 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#define _GNU_SOURCE
-
+#if defined(HAVE_CONFIG_H)
 #include "config.h"
+#endif
 
 #include <linux/input.h> /* This must be included before ncurses.h */
 #if defined HAVE_NCURSESW_CURSES_H
@@ -52,7 +52,6 @@
 #include <log/log.h>
 #include <util/util.h>
 
-#include "config.h"
 #include "nc-cui.h"
 #include "nc-widgets.h"
 
@@ -78,6 +77,9 @@ struct nc_widgetset {
        void    (*widget_focus)(struct nc_widget *, void *);
        void    *widget_focus_arg;
        FIELD   *cur_field;
+
+       /* custom validators */
+       FIELDTYPE *ipv4_multi_type;
 };
 
 struct nc_widget {
@@ -106,6 +108,7 @@ struct nc_widget_checkbox {
 };
 
 struct nc_widget_textbox {
+       struct nc_widgetset     *set;
        struct nc_widget        widget;
 };
 
@@ -130,6 +133,12 @@ struct nc_widget_button {
 };
 
 static void widgetset_add_field(struct nc_widgetset *set, FIELD *field);
+static void widgetset_remove_field(struct nc_widgetset *set, FIELD *field);
+
+static bool key_is_select(int key)
+{
+       return key == ' ' || key == '\r' || key == '\n' || key == KEY_ENTER;
+}
 
 static bool process_key_nop(struct nc_widget *widget __attribute__((unused)),
                FORM *form __attribute((unused)),
@@ -205,7 +214,7 @@ static bool checkbox_process_key(struct nc_widget *widget,
 {
        struct nc_widget_checkbox *checkbox = to_checkbox(widget);
 
-       if (key != ' ')
+       if (!key_is_select(key))
                return false;
 
        checkbox->checked = !checkbox->checked;
@@ -323,6 +332,7 @@ struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set,
        FIELD *f;
 
        textbox = talloc_zero(set, struct nc_widget_textbox);
+       textbox->set = set;
        textbox->widget.height = 1;
        textbox->widget.width = len;
        textbox->widget.x = x;
@@ -343,6 +353,62 @@ struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set,
        return textbox;
 }
 
+void widget_textbox_set_validator_integer(struct nc_widget_textbox *textbox,
+               long min, long max)
+{
+       set_field_type(textbox->widget.field, TYPE_INTEGER, 1, min, max);
+}
+
+void widget_textbox_set_validator_ipv4(struct nc_widget_textbox *textbox)
+{
+       set_field_type(textbox->widget.field, TYPE_IPV4);
+}
+
+static bool check_ipv4_multi_char(int c,
+               const void *arg __attribute__((unused)))
+{
+       return isdigit(c) || c == '.' || c == ' ';
+}
+
+static bool check_ipv4_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;
+               }
+       }
+
+       return true;
+}
+
+void widget_textbox_set_validator_ipv4_multi(struct nc_widget_textbox *textbox)
+{
+       if (!textbox->set->ipv4_multi_type) {
+               textbox->set->ipv4_multi_type = new_fieldtype(
+                               check_ipv4_multi_field,
+                               check_ipv4_multi_char);
+       }
+       set_field_type(textbox->widget.field, textbox->set->ipv4_multi_type);
+}
+
 static void select_option_change(struct select_option *opt, bool selected)
 {
        const char *str;
@@ -360,13 +426,8 @@ static bool select_process_key(struct nc_widget *w, FORM *form, int key)
        int i, new_idx;
        FIELD *field;
 
-       switch (key) {
-       case ' ':
-       case KEY_ENTER:
-               break;
-       default:
+       if (!key_is_select(key))
                return false;
-       }
 
        field = current_field(form);
        new_opt = NULL;
@@ -526,6 +587,27 @@ void widget_select_on_change(struct nc_widget_select *select,
        select->on_change_arg = arg;
 }
 
+void widget_select_drop_options(struct nc_widget_select *select)
+{
+       struct nc_widgetset *set = select->set;
+       int i;
+
+       for (i = 0; i < select->n_options; i++) {
+               FIELD *field = select->options[i].field;
+               widgetset_remove_field(set, field);
+               if (field == set->cur_field)
+                       set->cur_field = NULL;
+               free_field(select->options[i].field);
+       }
+
+       talloc_free(select->options);
+       select->options = NULL;
+       select->n_options = 0;
+       select->widget.height = 0;
+       select->widget.focus_y = 0;
+
+}
+
 static bool button_process_key(struct nc_widget *widget,
                FORM *form __attribute__((unused)), int key)
 {
@@ -534,15 +616,11 @@ static bool button_process_key(struct nc_widget *widget,
        if (!button->click)
                return false;
 
-       switch (key) {
-       case ' ':
-       case '\r':
-       case '\n':
-               button->click(button->arg);
-               return true;
-       }
+       if (!key_is_select(key))
+               return false;
 
-       return false;
+       button->click(button->arg);
+       return true;
 }
 
 static int button_destructor(void *ptr)
@@ -655,6 +733,8 @@ 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);
        return 0;
 }
 
@@ -672,6 +752,13 @@ struct nc_widgetset *widgetset_create(void *ctx, WINDOW *main, WINDOW *sub)
        return set;
 }
 
+void widgetset_set_windows(struct nc_widgetset *set,
+               WINDOW *main, WINDOW *sub)
+{
+       set->mainwin = main;
+       set->subwin = sub;
+}
+
 void widgetset_set_widget_focus(struct nc_widgetset *set,
                widget_focus_cb cb, void *arg)
 {
@@ -723,6 +810,23 @@ static void widgetset_add_field(struct nc_widgetset *set, FIELD *field)
        set->fields[set->n_fields] = NULL;
 }
 
+static void widgetset_remove_field(struct nc_widgetset *set, FIELD *field)
+{
+       int i;
+
+       for (i = 0; i < set->n_fields; i++) {
+               if (set->fields[i] == field)
+                       break;
+       }
+
+       if (i == set->n_fields)
+               return;
+
+       memmove(&set->fields[i], &set->fields[i+i],
+                       (set->n_fields - i) * sizeof(set->fields[i]));
+       set->n_fields--;
+}
+
 #define DECLARE_BASEFN(type) \
        struct nc_widget *widget_ ## type ## _base              \
                (struct nc_widget_ ## type *w)                  \