c - ncurses: custom validation type for dates - Stack Overflow

admin2025-04-15  4

As title suggests I need to leave a field in the form when a valid date is typed. I don't know if it is necessary to write from scratch a new validation type with:

typedef int (*HOOK)();       /* pointer to function returning int */

FIELDTYPE *new_fieldtype(HOOK f_validate, /* field validator */
                         HOOK c_validate) /* character validator */

or there is a simpler way to avoid the focus moving onto the next field if a function return false when an invalid date is typed. I have the function isValidDate(…) taken from here and I read the HowTo about to create a Custom Validation Type but it's still too complex for me.

I need an example about how to proceed:

  • avoid leaving the field when a function returns false (without custom validation)
  • or, custom validation type needed and how to bind it to my function isValidDate(…)

Here the code I've written so far:

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

// Macro to check if a given year is a leap year.
#define isLeapYear( year ) ( ( (year) % 4 == 0 && (year) % 100 != 0 ) || ( (year) % 400 == 0 ) )

// Define a structure to represent date
struct Date {
        int day;
        int month;
        int year;
};

// Function to validate a date
bool isValidDate( struct Date date )
{
        // the 1st element represents the number of days in January,
        // second for Feb and so on, the last element represents days in Dec
        int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

        // Check if year is valid (greater than 0)
        if (date.year <= 0)
                return false;

        // Check if month is between 1 and 12
        if (date.month < 1 || date.month > 12)
                return false;

        // Check if day is within the range for the given month
        if (date.day >= 1 && date.day <= daysInMonth[date.month - 1])
                return true;

        // Check for February in case of leap year
        if (date.month == 2 && isLeapYear(date.year))
                if (date.day < 1 || date.day > 29)
                        return false;

        // If all conditions are met, the date is valid
        return true;
}

int main()
{
        FIELD *field[3];
        FORM  *input_form;
        int ch, code = 0;
        bool Ins = true;

        // Initialize curses
        initscr();
        cbreak();
        noecho();
        keypad(stdscr, TRUE);

        // Initialize the fields
        field[0] = new_field(1, 16, 4, 19, 0, 0);
        field[1] = new_field(1, 10, 6, 33, 0, 0);
        field[2] = NULL;

        // Set field options
        set_field_back(field[0], A_UNDERLINE);  // Print a line for the option
        field_opts_off(field[0], O_AUTOSKIP);   // Don't go to next field when this field is filled up

        set_field_back(field[1], A_UNDERLINE);

        // Create the form and post it
        input_form = new_form(field);
        post_form(input_form);
        refresh();

        mvprintw(6, 10, "Birth date DD/MM/YYYY:");
        mvprintw(4, 10, "Name...: ");
        refresh();

        // Loop through to get user requests
        while( (ch = getch()) != KEY_F(1) )
        {
                switch(ch)
                {
                        case '\n':
                        case '\t':
                        case KEY_DOWN:
                                // Go to next field
                                form_driver(input_form, REQ_NEXT_FIELD);
                                // Go to the end of the present buffer, leaves nicely at the last character
                                form_driver(input_form, REQ_END_LINE);
                                break;
                        case KEY_BTAB:
                        case KEY_UP:
                                // Go to previous field
                                form_driver(input_form, REQ_PREV_FIELD);
                                form_driver(input_form, REQ_END_LINE);
                                break;
                        case KEY_BACKSPACE:
                        case 127:
                                form_driver(input_form, REQ_PREV_CHAR);
                                form_driver(input_form, REQ_DEL_CHAR);
                                break;
                        case KEY_HOME:
                                form_driver(input_form, REQ_BEG_LINE);
                                break;
                        case KEY_END:
                                form_driver(input_form, REQ_END_LINE);
                                break;
                        case KEY_LEFT:
                                form_driver(input_form, REQ_PREV_CHAR);
                                break;
                        case KEY_RIGHT:
                                form_driver(input_form, REQ_NEXT_CHAR);
                                break;
                        case KEY_IC:    // Ins key: toggle between insertion/overwrite mode
                                form_driver(input_form, ( Ins = ! Ins ) ? REQ_INS_MODE : REQ_OVL_MODE );
                                break;
                        case KEY_DC:    // Canc key
                                form_driver(input_form, REQ_DEL_CHAR);
                                form_driver(input_form, REQ_PREV_CHAR);
                                break;
                        default:
                                // If this is a normal character, it gets printed.
                                form_driver(input_form, ch);
                                form_driver(input_form, REQ_VALIDATION);
                                break;
                }
        }

        // Un post form and free the memory
        unpost_form(input_form);
        free_form(input_form);
        free_field(field[0]);
        free_field(field[1]);
        free_field(field[2]);

        endwin();
        exit_curses( code );

        return 0;
}

To compile I use the following command:

gcc -Wall -pedantic -Wextra filename.c -lform -lncurses
转载请注明原文地址:http://anycun.com/QandA/1744731992a86837.html