C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
fields.c
Go to the documentation of this file.
1/** @file fields.c
2 @brief Field Edit and Entry for C-Menu Form
3 @author Bill Waller
4 Copyright (c) 2025
5 MIT License
6 billxwaller@gmail.com
7 @date 2026-02-09
8 */
9
10#include <common.h>
11#include <monetary.h>
12#include <stdbool.h>
13#include <stddef.h>
14#include <stdio.h>
15#include <string.h>
16#include <termios.h>
17#include <unistd.h>
18
19bool is_valid_date(int, int, int);
20bool is_valid_time(int, int, int);
21int form_fmt_field(Form *, char *);
22void numeric(char *, char *);
23void right_justify(char *, int);
24void left_justify(char *);
25
26char ff_tbl[][26] = {"string", "decimal_int", "hex_int", "float", "double",
27 "currency", "yyyymmdd", "hhmmss", "apr", ""};
28
29int field_editor(Form *);
30int form_display_field(Form *);
32int form_display_field_n(Form *, int);
33int form_validate_field(Form *);
34
35/** @defgroup field_editor Field Editor
36 @brief File mapping, user input, command processing, and display logic
37 @brief Main loop for field editing and entry
38 @details This function handles the main loop for field editing and entry.
39 It processes user input, including character input, navigation keys, and
40 mouse events, to allow the user to edit the content of a field. The function
41 validates input based on the field's specified format and updates the display
42 accordingly. It returns the key code of the action taken, such as accepting
43 the field, tabbing to the next field, or breaking out of the input loop.
44 */
45
46/** @brief Accept input for a field
47 @ingroup field_editor
48 @param form Pointer to Form structure
49 @return int Key code of action taken
50 @details Handles character input, navigation keys, and mouse events for
51 field editing. Validates input based on field format and updates display.
52 Returns key code of action taken (e.g., accept field, tab to next field,
53 break out of input loop).
54 */
55int field_editor(Form *form) {
56 bool f_insert = FALSE;
57 int in_key;
58 char *s, *d;
59 if (form->fidx < 0 || form->fidx >= form->fcnt)
60 form->fcnt = 0;
61 int flin = form->field[form->fidx]->line;
62 int fcol = form->field[form->fidx]->col;
63 int flen = form->field[form->fidx]->len;
64 int ff = form->field[form->fidx]->ff;
65 char *accept_s = form->field[form->fidx]->accept_s;
66 // char *filler_s = form->field[form->fidx]->filler_s;
67 form_fmt_field(form, accept_s);
68 click_x = click_y = -1;
69 char *fstart = accept_s;
70 char *fend = fstart + flen;
71 int x = fcol;
72 char *p = fstart = accept_s;
73 char *str_end = p + strlen(p);
74 in_key = 0;
75 if (f_insert)
77 else
81
82 while (1) {
83 if (in_key == 0) {
84 // mvwaddstr(form->win, flin, fcol, filler_s);
85 form_fmt_field(form, accept_s);
87 tcflush(0, TCIFLUSH);
88 wmove(form->win, flin, x);
89
90 curs_set(1);
91 update_panels();
92 doupdate();
93 in_key = xwgetch(form->win, form->chyron, -1);
94 }
95 curs_set(0);
96 switch (in_key) {
97 /** KEY_F(10) is the default key for accepting the field and moving
98 to the next field */
99 case KEY_F(10):
100 form_fmt_field(form, accept_s);
102 if (form_validate_field(form) != 0)
103 continue;
104 return (in_key);
105 /** KEY_F(9) Cancels the current operation */
106 case KEY_BREAK:
107 case KEY_F(9):
109 in_key = KEY_F(9);
110 return (in_key);
111 /** KEY_UP, KEY_BTAB moves to the previous field */
112 case 'H':
113 case KEY_F(1):
114 return (in_key);
115 case KEY_BTAB:
116 case KEY_UP:
117 form_fmt_field(form, accept_s);
119 in_key = KEY_UP;
120 return (in_key);
121 /** KEY_DOWN, TAB moves to the next field */
122 case '\t':
123 case KEY_DOWN:
124 form_fmt_field(form, accept_s);
126 in_key = KEY_DOWN;
127 return (in_key);
128 /** KEY_END moves cursor to end of field */
129 case KEY_END:
130 case Ctrl('e'):
131 while (*p != '\0')
132 p++;
133 x = fcol + (p - fstart);
134 in_key = 0;
135 continue;
136 /**< Enter accepts the field and moves to the next field if
137 * form->f_erase_remainder is set, it will clear the remaining
138 * characters above and after the current cursor location */
139 case '\n':
140 case KEY_ENTER:
141 if (form->f_erase_remainder)
142 *p = '\0';
143 form_fmt_field(form, accept_s);
145 in_key = KEY_ENTER;
146 return (in_key);
147 /** KEY_IC toggles insert mode */
148 case KEY_IC:
149 if (f_insert) {
150 f_insert = FALSE;
151 set_chyron_key_cp(form->chyron, 18, "INS", KEY_IC, cp_nt_rev);
152 } else {
153 f_insert = TRUE;
154 set_chyron_key_cp(form->chyron, 18, "INS", KEY_IC,
156 }
159 form->chyron->l);
160 in_key = 0;
161 continue;
162 /** KEY_DC deletes character at cursor */
163 case KEY_DC:
164 s = p + 1;
165 d = p;
166 while (*s != '\0')
167 *d++ = *s++;
168 *d = '\0';
169 str_end = d;
170 f_insert = FALSE;
171 in_key = 0;
172 continue;
173 /** KEY_HOME moves cursor to start of field */
174 case KEY_HOME:
175 case Ctrl('a'):
176 p = fstart;
177 x = fcol;
178 in_key = 0;
179 continue;
180 /** KEY_BACKSPACE deletes character before cursor */
181 case KEY_BACKSPACE:
182 if (p > fstart) {
183 p--;
184 x--;
185 }
186 s = p + 1;
187 d = p;
188 while (*s != '\0')
189 *d++ = *s++;
190 *d = '\0';
191 str_end = d;
192 in_key = 0;
193 continue;
194 /** KEY_LEFT moves cursor left one character */
195 case KEY_LEFT:
196 if (p > fstart) {
197 p--;
198 x--;
199 }
200 in_key = 0;
201 continue;
202 /** KEY_RIGHT moves cursor right one character */
203 case KEY_RIGHT:
204 if (p < fend && p < str_end) {
205 p++;
206 x++;
207 }
208 in_key = 0;
209 continue;
210 /** Handles mouse events for field editing */
211 case KEY_MOUSE:
213 x = click_x;
214 flin = click_y;
215 flen = form->field[form->fidx]->len;
216 ff = form->field[form->fidx]->ff; /* ff - field forat */
217 accept_s = form->field[form->fidx]->accept_s;
218 // filler_s = form->field[form->fidx]->filler_s;
219 form_fmt_field(form, accept_s);
220 fstart = accept_s;
221 fend = fstart + flen;
222 str_end = fstart + strlen(fstart);
223 p = fstart + (x - form->field[form->fidx]->col);
224 if (p > str_end)
225 x -= p - str_end;
226 p = min(p, str_end);
227 in_key = 0;
228 continue;
229 default:
230 if (p >= fend) {
231 in_key = 0;
232 continue;
233 }
234 /** Validates fields based on format */
235 switch (ff) {
236 /** FF_STRING accepts all printable characters and spaces */
237 case FF_STRING:
238 break;
239 /** FF_DECIMAL_INT accepts digits 0 through 9 and decimal point
240 * ('.') */
241 case FF_DECIMAL_INT:
242 if ((in_key >= '0' && in_key <= '9') || in_key == '.')
243 break;
244 beep();
245 in_key = 0;
246 continue;
247 /** FF_HEX_INT accepts digits 0 through 9 and letters A through
248 * F (case-insensitive) */
249 case FF_HEX_INT:
250 if ((in_key >= '0' && in_key <= '9') ||
251 (in_key >= 'A' && in_key <= 'F') ||
252 (in_key >= 'a' && in_key <= 'f'))
253 break;
254 beep();
255 in_key = 0;
256 continue;
257 /** FF_FLOAT accepts digits 0 through 9 and decimal point ('.')
258 * and negative operator ('-') at the start of the field */
259 case FF_FLOAT:
260 if ((in_key >= '0' && in_key <= '9') || in_key == '.' ||
261 (in_key == '-' && p == fstart))
262 break;
263 beep();
264 in_key = 0;
265 continue;
266 /** FF_DOUBLE accepts digits 0 through 9 and decimal point ('.')
267 * and negative operator ('-') at the start of the field */
268 case FF_DOUBLE:
269 if ((in_key >= '0' && in_key <= '9') || in_key == '.' ||
270 (in_key == '-' && p == fstart))
271 break;
272 beep();
273 in_key = 0;
274 continue;
275 /** FF_CURRENCY accepts digits 0 through 9 and decimal point
276 * ('.') and negative operator ('-') at the start of the field
277 */
278 case FF_CURRENCY:
279 if ((in_key >= '0' && in_key <= '9') || in_key == '.' ||
280 (in_key == '-' && p == fstart))
281 break;
282 beep();
283 in_key = 0;
284 continue;
285 /** FF_YYYYMMDD accepts digits 0 through 9 */
286 case FF_YYYYMMDD:
287 if (in_key >= '0' && in_key <= '9')
288 break;
289 beep();
290 in_key = 0;
291 continue;
292 /** FF_HHMMSS accepts digits 0 through 9 */
293 case FF_HHMMSS:
294 if (in_key >= '0' && in_key <= '9')
295 break;
296 beep();
297 in_key = 0;
298 continue;
299 /** FF_APR accepts digits 0 through 9 and decimal point ('.') */
300 case FF_APR:
301 if ((in_key >= '0' && in_key <= '9') || in_key == '.')
302 break;
303 beep();
304 in_key = 0;
305 continue;
306 default:
307 Perror("field_editor() invalid format");
308 break;
309 }
310 if (in_key < ' ' || in_key > '~') {
311 in_key = 0;
312 continue;
313 }
314 if (f_insert) {
315 if (str_end < fend) {
316 s = str_end - 1;
317 d = str_end;
318 while (s >= p)
319 *d-- = *s--;
320 *p++ = in_key;
321 str_end++;
322 x++;
323 }
324 } else {
325 if (p < fend) {
326 if (p < str_end) {
327 if (p == accept_s && in_key == ' ') {
328 d = accept_s;
329 s = accept_s + 1;
330 while (*s != '\0')
331 *d++ = *s++;
332 *d = '\0';
333 in_key = 0;
334 continue;
335 }
336 *p++ = in_key;
337 x++;
338 } else if (p == str_end) {
339 *p++ = in_key;
340 *p = '\0';
341 str_end = p;
342 x++;
343 }
344 }
345 }
346 in_key = 0;
347 continue;
348 }
349 }
350}
351
352/** @brief Display field n
353 @ingroup field_editor
354 @param form Pointer to Form structure
355 @param n Field index to display
356 @return 0 on success, non-zero on error
357 @details This function temporarily sets the form's current field index
358 (fidx) to n, calls form_display_field() to display that field, and then
359 restores the original fidx value. This allows for displaying a specific field
360 without permanently changing the form's current field index.
361 */
362int form_display_field_n(Form *form, int n) {
363 int fidx = form->fidx;
364 form->fidx = n;
366 form->fidx = fidx;
367 return 0;
368}
369void display_field(Form *form, cchar_t *cmplx_buf, int y, int x) {
370
371 mvwadd_wchstr(form->win, y, x, cmplx_buf);
372}
373/** @brief Display current field
374 @ingroup field_editor
375 @param form Pointer to Form structure
376 @return 0 on success, non-zero on error
377 @details This function displays the current field based on the form's
378 current field index (fidx). It retrieves the line and column information for
379 the current field, displays any brackets if set, and then displays the
380 field's content using the display_s string. The function ensures that the
381 field is displayed correctly within the form's window and refreshes the
382 display to show the updated field content.
383 */
384int form_display_field(Form *form) {
385 int y = form->field[form->fidx]->line;
386 int x = form->field[form->fidx]->col;
387 mvwadd_wchnstr(form->win, y, x, form->field[form->fidx]->filler_cc, form->field[form->fidx]->len);
389 form->field[form->fidx]->len);
390 mvwadd_wchnstr(form->win, y, x, form->field[form->fidx]->display_cc, form->field[form->fidx]->len);
391 return 0;
392}
394 int y = form->field[form->fidx]->line;
395 int x = form->field[form->fidx]->col;
396 mvwaddstr(form->win, y, x, form->field[form->fidx]->filler_s);
397 mvwaddstr(form->win, y, x, form->field[form->fidx]->accept_s);
398 return 0;
399}
400/** @brief Format field according to its format type
401 @ingroup field_editor
402 @param form Pointer to Form structure
403 @param s Input string to format
404 @return 0 on success, non-zero on error
405 @details takes the input string for the current field and formats it
406 according to the field's specified format type (ff). It updates the
407 accept_s and display_s strings for the field based on the formatted
408 value.
409 Handles various format types, including strings, decimal integers,
410 hexadecimal integers, floating-point numbers, currency, dates, and times.
411 Uses helper functions for validation and formatting, such as
412 is_valid_date(), is_valid_time(), numeric(), right_justify(),
413 left_justify(), and strnzcpy(). The function ensures that the formatted
414 output fits within the field's length and creates a filler string for the
415 field as needed. The function also handles error cases, such as invalid
416 formats, and provides feedback through error messages. It is designed to
417 be extensible, allowing for additional format types to be added in the
418 future as needed.
419 Assumes that the input string is well-formed and does not contain
420 malicious content. Input validation and sanitization should be performed
421 at a higher level in the application to ensure security and robustness.
422 The function currently does not handle localization or
423 internationalization of number formats, such as different decimal
424 separators or currency symbols. Future enhancements may include support
425 for locale-specific formatting.
426 Error handling is basic; future
427 versions may include more detailed error reporting and logging
428 mechanisms.
429 Performance optimizations may be considered for
430 handling large volumes of data or high-frequency updates in real-time
431 applications. The following variables and structures are used in
432 this function:
433 @code
434 char field_s[FIELD_MAXLEN];
435 int decimal_int_n = 0;
436 int hex_int_n = 0;
437 float float_n = 0.0;
438 double double_n = 0.0;
439 double currency_n = 0.0;
440 struct Date { int yyyy; int mm; int dd; };
441 struct Time { int hh; int mm; int ss; };
442 @endcode
443 */
444int form_fmt_field(Form *form, char *s) {
446 char *input_s = form->field[form->fidx]->input_s;
447 char *accept_s = form->field[form->fidx]->accept_s;
448 char *display_s = form->field[form->fidx]->display_s;
449 // char *filler_s = form->field[form->fidx]->filler_s;
450 int ff = form->field[form->fidx]->ff;
451 int fl = form->field[form->fidx]->len;
452
453 char field_s[FIELD_MAXLEN];
454 int decimal_int_n = 0;
455 int hex_int_n = 0;
456 float float_n = 0.0;
457 double double_n = 0.0;
458 double currency_n = 0.0;
459 Date date;
460 date.yyyy = date.mm = date.dd = 0;
461 Time time;
462 time.hh = time.mm = time.ss = 0;
463
464 strnz(accept_s, fl);
465 switch (ff) {
466 case FF_STRING:
468 trim(s);
469 strnz__cpy(input_s, s, FIELD_MAXLEN - 1);
470 strnz__cpy(accept_s, s, FIELD_MAXLEN - 1);
471 strnz__cpy(display_s, s, FIELD_MAXLEN - 1);
472 break;
473 case FF_DECIMAL_INT:
474 sscanf(input_s, "%d", &decimal_int_n);
475 sprintf(accept_s, "%d", decimal_int_n);
476 sprintf(display_s, "%d", decimal_int_n);
477 right_justify(display_s, fl);
478 break;
479 case FF_HEX_INT:
480 sscanf(input_s, "%x", &hex_int_n);
481 sprintf(accept_s, "%d", hex_int_n);
482 sprintf(display_s, "%x", hex_int_n);
483 right_justify(display_s, fl);
484 break;
485 case FF_FLOAT:
486 sscanf(input_s, "%f", &float_n);
487 sprintf(accept_s, "%f", float_n);
488 sprintf(display_s, "%f", float_n);
489 right_justify(display_s, fl);
490 break;
491 case FF_DOUBLE:
492 sscanf(input_s, "%lf", &double_n);
493 sprintf(accept_s, "%lf", double_n);
494 sprintf(display_s, "%lf", double_n);
495 right_justify(display_s, fl);
496 break;
497 case FF_CURRENCY:
498 numeric(field_s, input_s);
499 sscanf(field_s, "%lf", &currency_n);
500 sprintf(accept_s, "%.2lf", currency_n);
501 sprintf(display_s, "%'.2lf", currency_n);
502 right_justify(display_s, fl);
503 break;
504 case FF_YYYYMMDD:
505 date.yyyy = date.mm = date.dd = 0;
506 strnz__cpy(field_s, input_s, FIELD_MAXLEN - 1);
507 sscanf(field_s, "%4d%2d%2d", &date.yyyy, &date.mm, &date.dd);
508 sprintf(accept_s, "%04d%02d%02d", date.yyyy, date.mm, date.dd);
509 if (is_valid_date(date.yyyy, date.mm, date.dd))
510 sprintf(display_s, "%04d-%02d-%02d", date.yyyy, date.mm, date.dd);
511 break;
512 case FF_HHMMSS:
513 time.hh = time.mm = time.ss = 0;
514 strnz__cpy(field_s, input_s, FIELD_MAXLEN - 1);
515 sscanf(field_s, "%2d%2d%2d", &time.hh, &time.mm, &time.ss);
516 sprintf(accept_s, "%02d%02d%02d", time.hh, time.mm, time.ss);
517 if (is_valid_time(time.hh, time.mm, time.ss))
518 sprintf(display_s, "%02d:%02d:%02d", time.hh, time.mm, time.ss);
519 break;
520 case FF_APR:
521 sscanf(input_s, "%lf", &double_n);
522 sprintf(accept_s, "%lf", double_n);
523 sprintf(display_s, "%0.3lf", double_n);
524 right_justify(display_s, fl);
525 break;
526 default:
527 Perror("form_fmt_field() invalid format");
528 break;
529 }
530 strnz(accept_s, fl);
531 left_justify(accept_s);
532 return 0;
533}
534/** @brief Validate current field based on flags
535 @ingroup field_editor
536 @param form Pointer to Form structure
537 @return 0 if valid, 1 if invalid
538 @details Very underdeveloped - only checks F_NOTBLANK and F_NOMETAS
539 */
540int form_validate_field(Form *form) {
541 int n = form->fidx;
542 char *p = form->field[n]->accept_s;
543 if (form->field[n]->ff & F_NOTBLANK) {
544 char *s = form->field[n]->accept_s;
545 while (*s++ == ' ')
546 ;
547 if (*s == '\0') {
548 Perror("blank field not allowed");
549 return (1);
550 }
551 }
552 if (form->field[n]->ff & F_NOMETAS) {
553 if (strpbrk(p, "*?[]") != 0) {
554 Perror("metacharacters not allowed");
555 return (1);
556 }
557 }
558 return (0);
559}
560/** @brief Left justify string by removing leading spaces
561 @ingroup field_editor
562 @param s String to left justify
563 @details This function takes a string s and removes any leading spaces,
564 effectively left-justifying the text. It does this by finding the first
565 non-space character and shifting the string to the left, overwriting the
566 leading spaces. The resulting string is null-terminated.
567 */
568void left_justify(char *s) { trim(s); }
569/** @brief Right justify string by removing trailing spaces and adding leading
570 @ingroup field_editor
571 spaces
572 @param s String to right justify
573 @param fl Field length
574 @details This function takes a string s and right-justifies it within a
575 field of length fl. It first removes any trailing spaces from the string,
576 then shifts the characters to the right end of the field, filling the left
577 side with spaces. The resulting string is null-terminated and fits within the
578 specified field length.
579 */
580void right_justify(char *, int);
581void right_justify(char *s, int fl) {
582 char *p = s;
583 char *d = s + fl;
584 trim(s);
585 *d = '\0';
586 while (*s != '\0') {
587 s++;
588 }
589 while (s != p) {
590 *(--d) = *(--s);
591 }
592 while (d != p) {
593 *(--d) = ' ';
594 }
595}
596/** @brief Check if a given date is valid, including leap years
597 @ingroup field_editor
598 @param yyyy Year
599 @param mm Month
600 @param dd Day
601 @return true if the date is valid, false otherwise
602 @details This function checks if the provided year, month, and day
603 constitute a valid date. It accounts for leap years when determining the
604 number of days in February. The function returns true if the date is valid
605 and false if it is not.
606 */
607bool is_valid_date(int yyyy, int mm, int dd) {
608 if (yyyy < 1 || mm < 1 || mm > 12 || dd < 1)
609 return false;
610 int days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
611 if ((yyyy % 4 == 0 && yyyy % 100 != 0) || (yyyy % 400 == 0))
612 days_in_month[2] = 29;
613 if (dd > days_in_month[mm])
614 return false;
615 return true;
616}
617/** @brief Check if a given time is valid
618 @ingroup field_editor
619 @param hh Hour
620 @param mm Minute
621 @param ss Second
622 @return true if the time is valid, false otherwise
623 @details This function checks if the provided hour, minute, and second
624 constitute a valid time. It ensures that hours are between 0 and 23, minutes
625 and seconds are between 0 and 59. The function returns true if the time is
626 valid and false if it is not.
627 */
628bool is_valid_time(int hh, int mm, int ss) {
629 if (hh < 0 || hh > 23 || mm < 0 || mm > 59 || ss < 0 || ss > 59)
630 return false;
631 return true;
632}
633/** @brief Extract numeric characters from source string to destination string
634 @ingroup field_editor
635 @param d Destination string
636 @param s Source string
637 @details This function takes a source string s and extracts only the numeric
638 characters (digits 0-9), as well as dashes ('-') and periods ('.'), copying
639 them into the destination string d. The resulting string in d is
640 null-terminated. This is useful for processing input that may contain
641 non-numeric characters, allowing the application to focus on the numeric
642 content for further processing or validation.
643 */
644void numeric(char *d, char *s) {
645 while (*s != '\0') {
646 if (*s == '-' || *s == '.' || (*s >= '0' && *s <= '9'))
647 *d++ = *s++;
648 else
649 s++;
650 }
651 *d = '\0';
652}
int form_yx_to_fidx(Form *, int, int)
#define FIELD_MAXLEN
Definition form.h:18
@ FF_DECIMAL_INT
Definition form.h:50
@ FF_STRING
Definition form.h:48
@ FF_HEX_INT
Definition form.h:52
@ FF_YYYYMMDD
Definition form.h:61
@ FF_HHMMSS
Definition form.h:63
@ FF_CURRENCY
Definition form.h:58
@ FF_FLOAT
Definition form.h:54
@ FF_DOUBLE
Definition form.h:56
@ FF_APR
Definition form.h:65
#define F_NOTBLANK
Definition form.h:21
char ff_tbl[][26]
Definition fields.c:26
void display_field(Form *, cchar_t *, int, int)
Definition fields.c:369
#define F_NOMETAS
Definition form.h:20
int cp_nt
Definition dwin.c:183
int click_x
Definition dwin.c:81
int cp_nt_hl_rev
Definition dwin.c:186
int click_y
Definition dwin.c:80
#define min(x, y)
min macro evaluates two expressions, returning least result
Definition cm.h:89
int cp_nt_rev
Definition dwin.c:184
#define Ctrl(c)
Definition cm.h:52
#define TRUE
Definition iloan.c:19
#define FALSE
Definition iloan.c:18
int form_display_accept_field(Form *)
Definition fields.c:393
int xwgetch(WINDOW *, Chyron *, int)
Wrapper for wgetch that handles signals, mouse events, checks for clicks on the chyron line,...
Definition dwin.c:2094
size_t str_to_cc(cchar_t *, const char *, attr_t, int, size_t)
Convert a multibyte string to an array of cchar_t complex characters.
Definition dwin.c:786
int Perror(char *)
Display a simple error message window or print to stderr.
Definition dwin.c:1526
void display_chyron(WINDOW *, Chyron *, int, int)
Display chyron on window.
Definition dwin.c:1892
void set_chyron_key_cp(Chyron *, int, char *, int, int)
Set chyron key with color pair (cp).
Definition dwin.c:1759
void compile_chyron(Chyron *)
construct the chyron string from the chyron structure
Definition dwin.c:1848
int form_fmt_field(Form *, char *s)
Format field according to its format type.
Definition fields.c:444
int field_editor(Form *)
Accept input for a field.
Definition fields.c:55
void numeric(char *d, char *s)
Extract numeric characters from source string to destination string.
Definition fields.c:644
bool is_valid_date(int yyyy, int mm, int dd)
Check if a given date is valid, including leap years.
Definition fields.c:607
void left_justify(char *s)
Left justify string by removing leading spaces.
Definition fields.c:568
bool is_valid_time(int hh, int mm, int ss)
Check if a given time is valid.
Definition fields.c:628
int form_display_field_n(Form *, int)
Display field n.
Definition fields.c:362
void right_justify(char *, int)
Right justify string by removing trailing spaces and adding leadingspaces.
Definition fields.c:581
int form_display_field(Form *)
Display current field.
Definition fields.c:384
int form_validate_field(Form *)
Validate current field based on flags.
Definition fields.c:540
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition futil.c:544
size_t trim(char *)
Trims leading and trailing spaces from string s in place.
Definition futil.c:391
size_t strnz(char *, size_t)
terminates string at New Line, Carriage Return, or max_len
Definition futil.c:615
int dd
Definition cm.h:58
int yyyy
Definition cm.h:56
int mm
Definition cm.h:57
int ss
Definition cm.h:64
int mm
Definition cm.h:63
int hh
Definition cm.h:62
int l
Definition cm.h:348
int line
Definition form.h:113
char display_s[FIELD_MAXLEN]
Definition form.h:130
char accept_s[FIELD_MAXLEN]
Definition form.h:126
int ff
Definition form.h:119
int col
Definition form.h:115
char input_s[FIELD_MAXLEN]
Definition form.h:123
cchar_t filler_cc[FIELD_MAXLEN]
Definition form.h:141
cchar_t display_cc[FIELD_MAXLEN]
Definition form.h:135
int len
Definition form.h:117
char filler_s[FIELD_MAXLEN]
Definition form.h:136
bool f_erase_remainder
Definition form.h:235
Field * field[FIELD_MAXCNT]
Definition form.h:351
int lines
Definition form.h:149
int fcnt
Definition form.h:316
int fidx
Definition form.h:308
Chyron * chyron
Definition form.h:363
WINDOW * win
Definition form.h:155