alexanderzhirov
alexanderzhirov

Reputation: 198

Form validation using Ncurses (FORM)

Cannot implement character input validation. I have sketched out the code of a simple program for input validation. Various characters are displayed in the field.

#include <form.h>

int main() {
    initscr();
    curs_set(1);
    WINDOW *win = newwin(5, 40, 10, 10);
    keypad(win, TRUE);
    box(win, 0, 0);
    wrefresh(win);

    FIELD *fields[2];
    fields[0] = new_field(1, 20, 2, 2, 0, 0);
    fields[1] = NULL;
    set_field_type(fields[0], TYPE_REGEXP, "^[0-9]*$");
    set_field_opts(fields[0], O_VISIBLE | O_ACTIVE | O_EDIT);

    FORM *form = new_form(fields);
    set_form_win(form, win);
    set_form_sub(form, derwin(win, 3, 38, 1, 1));
    post_form(form);
    wrefresh(win);

    int ch;
    while ((ch = wgetch(win)) != KEY_F(1)) {
        int status = form_driver(form, ch);
        if (status == E_INVALID_FIELD) {
            form_driver(form, REQ_VALIDATION);
        } else if (status == E_OK) {
            wrefresh(win);
        }
    }

    unpost_form(form);
    free_form(form);
    free_field(fields[0]);
    endwin();

    return 0;
}

enter image description here

UPD 1:

    while ((ch = wgetch(win)) != KEY_F(1)) {
        int status = form_driver(form, ch);
        if( status == E_OK ) {
            status = form_driver(form, REQ_VALIDATION);
        }
        if (status == E_INVALID_FIELD) {
            frefresh(form);
        } else if (status == E_OK) {
            wrefresh(win);
        }
    }
void frefresh(FORM *form) {
    form_driver(form, REQ_DEL_PREV);
}

Moved the cleaning code to a separate function. The cursor returns to the incorrectly entered character.

enter image description here

Upvotes: 0

Views: 75

Answers (2)

alexanderzhirov
alexanderzhirov

Reputation: 198

It was possible to implement processing of spaces and hiding passwords behind spaces. Thus, it was possible to check data during input and hide the entered data.

enter image description here

enter image description here

In the future, correction of incorrect input using other keys is necessary.

C language:

#include <form.h>
#include <stdio.h>

#define SIZEPASS 20

int main() {
    initscr();
    raw();
    noecho();
    curs_set(2);
    WINDOW *win = newwin(5, 40, 10, 10);
    keypad(win, TRUE);
    box(win, 0, 0);
    wrefresh(win);

    FIELD *fields[2];
    fields[0] = new_field(1, SIZEPASS, 2, 2, 0, 0);
    fields[1] = NULL;
    set_field_type(fields[0], TYPE_REGEXP, "^\\\\*[0-9A-Za-z*]* *$");
    set_field_opts(fields[0], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
    set_field_back(fields[0], A_UNDERLINE);

    FORM *form = new_form(fields);
    set_form_win(form, win);
    set_form_sub(form, derwin(win, 3, 38, 1, 1));
    post_form(form);
    wrefresh(win);

    char password[SIZEPASS] = {};
    int ch, status, count = 0, stop = 0;

    while (!stop && (ch = wgetch(win)) != KEY_F(2)) {
        switch (ch) {
            case KEY_BACKSPACE:
                form_driver(form, REQ_DEL_PREV);
                if (count)
                    password[--count] = '\0';
                break;
            case 32:
                break;
            case 10:
            case KEY_ENTER:
                stop = 1;
                break;
            default:
                status = form_driver(form, ch);
                if( status == E_OK ) {
                    status = form_driver(form, REQ_VALIDATION);
                }
                if (status == E_INVALID_FIELD) {
                    form_driver(form, REQ_DEL_PREV);
                } else {
                    password[count++] = (char)ch;
                    password[count] = '\0';
                    form_driver(form, REQ_DEL_PREV);
                    form_driver(form, '*');
                }
        }
    }

    unpost_form(form);
    free_form(form);
    free_field(fields[0]);
    endwin();

    printf("Password: %s\n", password);

    return 0;
}

D language:

module source.app;

import std.conv;
import std.string;
import std.stdio;

public import deimos.ncurses;
public import deimos.form;
public import core.stdc.locale;

int main(string[] args) {
    setlocale(LC_CTYPE,"");
    initscr();
    raw();
    noecho();
    curs_set(2);
    WINDOW *win = newwin(5, 40, 10, 10);
    keypad(win, TRUE);
    box(win, 0, 0);
    wrefresh(win);

    FIELD*[2] fields;
    fields[0] = new_field(1, 20, 2, 2, 0, 0);
    fields[1] = null;
    set_field_type(fields[0], TYPE_REGEXP, `^\**[0-9A-Za-z*]* *$`.ptr);
    set_field_opts(fields[0], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
    set_field_back(fields[0], A_UNDERLINE);

    FORM *form = new_form(cast(FIELD**)fields);
    set_form_win(form, win);
    set_form_sub(form, derwin(win, 3, 38, 1, 1));
    post_form(form);
    wrefresh(win);

    string password;
    bool stop = false;
    int ch, status;

    while (!stop && (ch = wgetch(win)) != KEY_F(2)) {
        switch (ch) {
            case KEY_BACKSPACE:
                form_driver(form, REQ_DEL_PREV);
                if (password.length)
                    password = password[0 .. $ - 1];
                break;
            case 32:
                break;
            case 10:
            case KEY_ENTER:
                stop = true;
                break;
            default:
                status = form_driver(form, ch);
                if( status == E_OK ) {
                    status = form_driver(form, REQ_VALIDATION);
                }
                if (status == E_INVALID_FIELD) {
                    form_driver(form, REQ_DEL_PREV);
                } else {
                    password ~= ch.to!char;
                    form_driver(form, REQ_DEL_PREV);
                    form_driver(form, '*'.to!int);
                }
                break;
        }
    }

    unpost_form(form);
    free_form(form);
    free_field(fields[0]);
    endwin();

    writeln("Password: " ~ password);

    return 0;
}

Implementation of wide characters in C (maybe it will be useful for someone searching).

D language (wide char, unicode):

module source.app;

import std.conv;
import std.string;

import std.stdio;

public import deimos.ncurses;
public import deimos.form;
public import core.stdc.locale;

int main(string[] args) {
    setlocale(LC_ALL,"");
    initscr();
    raw();
    noecho();
    curs_set(2);
    WINDOW *win = newwin(5, 40, 10, 10);
    keypad(win, TRUE);
    box(win, 0, 0);
    wrefresh(win);

    FIELD*[2] fields;
    fields[0] = new_field(1, 20, 2, 2, 0, 0);
    fields[1] = null;
    set_field_type(fields[0], TYPE_REGEXP, `^\**[0-9A-Za-zА-Яа-я*]* *$`.ptr);
    set_field_opts(fields[0], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
    set_field_back(fields[0], A_UNDERLINE);

    FORM *form = new_form(cast(FIELD**)fields);
    set_form_win(form, win);
    set_form_sub(form, derwin(win, 3, 38, 1, 1));
    post_form(form);
    wrefresh(win);

    dstring password;
    bool stop = false;

    int status;

    dchar ch;
    int ret;

    while (!stop) {
        ret = wget_wch(win, &ch);
        switch (ret) {
            case KEY_CODE_YES:
                break;
            case OK:
                switch (ch) {
                    case KEY_BACKSPACE:
                        form_driver_w(form, KEY_CODE_YES, REQ_DEL_PREV);
                        if (password.length)
                            password = password[0 .. $ - 1];
                        break;
                    case 32:
                        break;
                    case 10:
                    case KEY_ENTER:
                        stop = true;
                        break;
                    default:
                        status = form_driver_w(form, OK, ch);
                        if( status == OK ) {
                            status = form_driver_w(form, KEY_CODE_YES, REQ_VALIDATION);
                            if (status == OK) {
                                password ~= ch.to!dchar;
                                form_driver_w(form, KEY_CODE_YES, REQ_DEL_PREV);
                                form_driver_w(form, OK, '*'.to!int);
                            } else {
                                status = form_driver_w(form, KEY_CODE_YES, REQ_DEL_PREV);
                            }
                        }
                }
                break;
            default:
                break;
        }
    }

    unpost_form(form);
    free_form(form);
    free_field(fields[0]);
    endwin();

    writefln("Password: %s\n", password);

    return 0;
}

Upvotes: 0

Ingo Leonhardt
Ingo Leonhardt

Reputation: 9894

two issues:

  • form_driver(form, ch) doesn't validate the fields, only form_driver(form, REQ_VALIDATION); does
  • with the regexp you are using, field[0} must be completely filled with digits, so validation would cause an error as long as you haven't typed 20 digits. From man set_field_opts

Please notice that the regular expression must match the whole field. If you have for example an eight character wide field, a regular expression "^[0-9]$" always means that you have to fill all eight positions with digits. If you want to allow fewer digits, you may use for example "^[0-9] *$" which is good for trailing spaces (up to an empty field), or "^ [0-9] *$" which is good for leading and trailing spaces around the digits.

Regarding these points I have modifield your code like that:

#include <form.h>

int main() {
    initscr();
    curs_set(1);
    WINDOW *win = newwin(5, 40, 10, 10);
    keypad(win, TRUE);
    box(win, 0, 0);
    wrefresh(win);

    FIELD *fields[2];
    fields[0] = new_field(1, 20, 2, 2, 0, 0);
    fields[1] = NULL;
    set_field_type(fields[0], TYPE_REGEXP, "^[0-9]* *$");
    set_field_opts(fields[0], O_VISIBLE | O_ACTIVE | O_EDIT);

    FORM *form = new_form(fields);
    set_form_win(form, win);
    set_form_sub(form, derwin(win, 3, 38, 1, 1));
    post_form(form);
    wrefresh(win);

    int ch;
    while ((ch = wgetch(win)) != KEY_F(1)) {
        int status = form_driver(form, ch);
        if( status == E_OK ) {
            status = form_driver(form, REQ_VALIDATION);
        }
        if (status == E_INVALID_FIELD) {
            // handle invalid input
            fprintf( stderr, "invalid input: %c\n", ch );
        } else if (status == E_OK) {
            wrefresh(win);
        }
    }

    unpost_form(form);
    free_form(form);
    free_field(fields[0]);
    endwin();

    return 0;
}

When you run that and type 31K you will get on stderr

invalid input: K

Upvotes: 1

Related Questions