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/** @defgroup fields Field Edit and Entry
11 @brief Functions for handling field editing and entry
12 @details This module provides functions for handling field editing and entry
13 within in the C-Menu Form library. It includes functionality for accepting
14 user input for fields, displaying fields, formatting field content based on
15 specified formats, validating field input, and creating filler strings for
16 fields. The module supports various field formats such as strings, decimal
17 integers, hexadecimal integers, floating-point numbers, currency, dates, and
18 times. It also handles user interactions such as navigation keys and mouse
19 events for editing fields. The functions in this module are designed to be
20 used in conjunction with the overall C-Menu Form library to create
21 interactive forms in a text-based user interface.
22 */
23
24#include <common.h>
25#include <monetary.h>
26#include <stdbool.h>
27#include <stddef.h>
28#include <stdio.h>
29#include <string.h>
30#include <termios.h>
31#include <unistd.h>
32
33bool is_valid_date(int, int, int);
34bool is_valid_time(int, int, int);
35int form_fmt_field(Form *, char *);
36void numeric(char *, char *);
37void right_justify(char *, int);
38void left_justify(char *);
39
40char ff_tbl[][26] = {"string", "decimal_int", "hex_int", "float", "double",
41 "currency", "yyyymmdd", "hhmmss", "apr", ""};
42
43int field_editor(Form *);
44int form_display_field(Form *);
45int form_display_field_n(Form *, int);
47int form_validate_field(Form *);
48void mk_filler(char *, int);
49
50/** @brief Accept input for a field
51 @ingroup fields
52 @param form Pointer to Form structure
53 @return int Key code of action taken
54 @note Handles character input, navigation keys, and mouse events for field
55 editing. Validates input based on field format and updates display.
56 Returns key code of action taken (e.g., accept field, tab to next field,
57 break out of input loop).
58 */
59int field_editor(Form *form) {
60 bool f_insert = FALSE;
61 int in_key;
62 char *s, *d;
63 WINDOW *win = form->win;
64
65 int flin = form->field[form->fidx]->line;
66 int fcol = form->field[form->fidx]->col;
67 int flen = form->field[form->fidx]->len;
68 int ff = form->field[form->fidx]->ff;
69 char *accept_s = form->field[form->fidx]->accept_s;
70 char *filler_s = form->field[form->fidx]->filler_s;
71 form_fmt_field(form, accept_s);
72 click_x = click_y = -1;
73 char *fstart = accept_s;
74 char *fend = fstart + flen;
75 int x = fcol;
76 char *p = fstart = accept_s;
77 char *str_end = p + strlen(p);
78 in_key = 0;
79 if (f_insert)
80 set_chyron_key_cp(form->chyron, 18, "INS", KEY_IC,
82 else
86
87 while (1) {
88 if (in_key == 0) {
89 mvwaddstr(win, flin, fcol, filler_s);
90 mvwaddstr(win, flin, fcol, accept_s);
91 wmove(win, flin, x);
92 tcflush(0, TCIFLUSH);
93 wmove(win, flin, x);
94 in_key = xwgetch(win, form->chyron, -1);
95 }
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;
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 >= ' ') {
311 if (f_insert) {
312 if (str_end < fend) {
313 s = str_end - 1;
314 d = str_end;
315 while (s >= p)
316 *d-- = *s--;
317 *p++ = in_key;
318 str_end++;
319 x++;
320 }
321 } else {
322 if (p < fend) {
323 if (p < str_end) {
324 *p++ = in_key;
325 x++;
326 } else if (p == str_end) {
327 *p++ = in_key;
328 *p = '\0';
329 str_end = p;
330 x++;
331 }
332 }
333 }
334 in_key = 0;
335 continue;
336 }
337 }
338 }
339}
340
341/** @brief Display field n
342 @ingroup fields
343 @param form Pointer to Form structure
344 @param n Field index to display
345 @return 0 on success, non-zero on error
346 @note This function temporarily sets the form's current field index (fidx)
347 to n, calls form_display_field() to display that field, and then restores the
348 original fidx value. This allows for displaying a specific field without
349 permanently changing the form's current field index.
350 */
351int form_display_field_n(Form *form, int n) {
352 int fidx = form->fidx;
353 form->fidx = n;
355 form->fidx = fidx;
356 return 0;
357}
358/** @brief Display current field
359 @ingroup fields
360 @param form Pointer to Form structure
361 @return 0 on success, non-zero on error
362 @note This function displays the current field based on the form's current
363 field index (fidx). It retrieves the line and column information for the
364 current field, displays any brackets if set, and then displays the field's
365 content using the display_s string. The function ensures that the field is
366 displayed correctly within the form's window and refreshes the display to
367 show the updated field content.
368 */
369int form_display_field(Form *form) {
370 WINDOW *win = form->win;
371 int flin = form->field[form->fidx]->line;
372 int fcol = form->field[form->fidx]->col;
374 mvwaddstr(win, flin, fcol, form->field[form->fidx]->filler_s);
375 mvwaddstr(win, flin, fcol, form->field[form->fidx]->display_s);
376 // wrefresh(win);
377 return 0;
378}
379/** @brief Display brackets around current field if set
380 @ingroup fields
381 @param form Pointer to Form structure
382 @return 0 on success, non-zero on error
383 @note This function checks if the form's brackets array has non-empty values
384 for both the left and right brackets. If so, it retrieves the line and column
385 information for the current field and uses the form's box window to display
386 the left bracket at the start of the field and the right bracket at the end
387 of the field. The display is refreshed to show the brackets around the field.
388 */
390 int flin, fcol;
391 if (form->brackets[0] != '\0' && form->brackets[1] != '\0') {
392 WINDOW *box = form->box;
393 flin = form->field[form->fidx]->line + 1;
394 fcol = form->field[form->fidx]->col;
395 wmove(box, flin, fcol);
396 waddch(box, form->brackets[0]);
397 wmove(box, flin, fcol + form->field[form->fidx]->len + 1);
398 waddch(box, form->brackets[1]);
399 wrefresh(box);
400 }
401 return 0;
402}
403/** @brief Format field according to its format type
404 @ingroup fields
405 @param form Pointer to Form structure
406 @param s Input string to format
407 @return 0 on success, non-zero on error
408 @note This function takes the input string for the current field and formats
409 it according to the field's specified format type (ff). It updates the
410 accept_s and display_s strings for the field based on the formatted value.
411 The function handles various format types, including strings, decimal
412 integers, hexadecimal integers, floating-point numbers, currency, dates, and
413 times. It uses helper functions for validation and formatting, such as
414 is_valid_date(), is_valid_time(), numeric(), right_justify(), left_justify(),
415 and strnzcpy(). The function ensures that the formatted output fits within
416 the field's length and creates a filler string for the field as needed. The
417 function also handles error cases, such as invalid formats, and provides
418 feedback through error messages. It is designed to be extensible, allowing
419 for additional format types to be added in the future as needed.
420 */
421int form_fmt_field(Form *form, char *s) {
422 /** @brief Format field according to its format type
423 @ingroup fields
424 @param form Pointer to Form structure
425 @param s Input string to format
426 @return 0 on success, non-zero on error
427 @note takes the input string for the current field and formats it
428 according to the field's specified format type (ff). It updates the
429 accept_s and display_s strings for the field based on the formatted
430 value.
431 @note handles various format types, including strings, decimal integers,
432 hexadecimal integers, floating-point numbers, currency, dates, and times.
433 @note uses helper functions for validation and formatting, such as
434 is_valid_date(), is_valid_time(), numeric(), right_justify(),
435 left_justify(), and strnzcpy(). The function ensures that the formatted
436 output fits within the field's length and creates a filler string for the
437 field as needed. The function also handles error cases, such as invalid
438 formats, and provides feedback through error messages. It is designed to
439 be extensible, allowing for additional format types to be added in the
440 future as needed.
441 @note assumes that the input string is well-formed and does not contain
442 malicious content. Input validation and sanitization should be performed
443 at a higher level in the application to ensure security and robustness.
444 @note The function currently does not handle localization or
445 internationalization of number formats, such as different decimal
446 separators or currency symbols. Future enhancements may include support
447 for locale-specific formatting. @note Error handling is basic; future
448 versions may include more detailed error reporting and logging
449 mechanisms. @note Performance optimizations may be considered for
450 handling large volumes of data or high-frequency updates in real-time
451 applications. @note The following variables and structures are used in
452 this function:
453 @code
454 char field_s[FIELD_MAXLEN];
455 int decimal_int_n = 0;
456 int hex_int_n = 0;
457 float float_n = 0.0;
458 double double_n = 0.0;
459 double currency_n = 0.0;
460 struct Date { int yyyy; int mm; int dd; };
461 struct Time { int hh; int mm; int ss; };
462 @endcode
463 @note supports format types: FF_STRING, FF_DECIMAL_INT, FF_HEX_INT,
464 FF_FLOAT, FF_DOUBLE, FF_CURRENCY, FF_YYYYMMDD, FF_HHMMSS, FF_APR with
465 appropriate formatting and validation for each type. @note Handles field
466 length and filler string creation. @note As the roadmap indicates, these
467 data types are just a start and more complex types and formats may be
468 added in the future. @note These data types are not suitable for
469 financial, scientific, or high-precision applications. They are intended
470 for basic data entry and display in a text-based user interface.
471 @note In the future, we will aqdd support for additional data types and
472 formats such as: dates with time zones, timestamps, percentages,
473 scientific notation, and custom user-defined formats.
474 @note For high precision applications, we will be integrating support
475 for 128-bit binary coded decimal (BCD) types and arbitrary precision
476 decimal types using libraries such as the GNU MPFR library, IBM's
477 decNumber, Rust Decimal, or the Intel Decimal Floating-Point Math
478 Library.
479 @note C-Menu Form converts each field's input string into internal
480 numeric binary based on the field's specified format. The internal
481 numberic binary is then formated and displayed, verifying the user's
482 input and Form's interpretation of the user's input.
483 */
485 char *input_s = form->field[form->fidx]->input_s;
486 char *accept_s = form->field[form->fidx]->accept_s;
487 char *display_s = form->field[form->fidx]->display_s;
488 char *filler_s = form->field[form->fidx]->filler_s;
489 int ff = form->field[form->fidx]->ff;
490 int fl = form->field[form->fidx]->len;
491
492 char field_s[FIELD_MAXLEN];
493 int decimal_int_n = 0;
494 int hex_int_n = 0;
495 float float_n = 0.0;
496 double double_n = 0.0;
497 double currency_n = 0.0;
498
499 struct {
500 int yyyy;
501 int mm;
502 int dd;
503 } Date;
504 Date.yyyy = Date.mm = Date.dd = 0;
505 struct {
506 int hh;
507 int mm;
508 int ss;
509 } Time;
510 Time.hh = Time.mm = Time.ss = 0;
511 strnz(accept_s, fl);
512 switch (ff) {
513 case FF_STRING:
515 trim(s);
516 strnz__cpy(input_s, s, FIELD_MAXLEN - 1);
517 strnz__cpy(accept_s, s, FIELD_MAXLEN - 1);
518 strnz__cpy(display_s, s, FIELD_MAXLEN - 1);
519 break;
520 case FF_DECIMAL_INT:
521 sscanf(input_s, "%d", &decimal_int_n);
522 sprintf(accept_s, "%d", decimal_int_n);
523 sprintf(display_s, "%d", decimal_int_n);
524 right_justify(display_s, fl);
525 break;
526 case FF_HEX_INT:
527 sscanf(input_s, "%x", &hex_int_n);
528 sprintf(accept_s, "%d", hex_int_n);
529 sprintf(display_s, "%x", hex_int_n);
530 right_justify(display_s, fl);
531 break;
532 case FF_FLOAT:
533 sscanf(input_s, "%f", &float_n);
534 sprintf(accept_s, "%f", float_n);
535 sprintf(display_s, "%f", float_n);
536 right_justify(display_s, fl);
537 break;
538 case FF_DOUBLE:
539 sscanf(input_s, "%lf", &double_n);
540 sprintf(accept_s, "%lf", double_n);
541 sprintf(display_s, "%lf", double_n);
542 right_justify(display_s, fl);
543 break;
544 case FF_CURRENCY:
545 numeric(field_s, input_s);
546 sscanf(field_s, "%lf", &currency_n);
547 sprintf(accept_s, "%.2lf", currency_n);
548 sprintf(display_s, "%'.2lf", currency_n);
549 right_justify(display_s, fl);
550 break;
551 case FF_YYYYMMDD:
552 Date.yyyy = Date.mm = Date.dd = 0;
553 strnz__cpy(field_s, input_s, FIELD_MAXLEN - 1);
554 sscanf(field_s, "%4d%2d%2d", &Date.yyyy, &Date.mm, &Date.dd);
555 sprintf(accept_s, "%04d%02d%02d", Date.yyyy, Date.mm, Date.dd);
556 if (is_valid_date(Date.yyyy, Date.mm, Date.dd))
557 sprintf(display_s, "%04d-%02d-%02d", Date.yyyy, Date.mm, Date.dd);
558 break;
559 case FF_HHMMSS:
560 Time.hh = Time.mm = Time.ss = 0;
561 strnz__cpy(field_s, input_s, FIELD_MAXLEN - 1);
562 sscanf(field_s, "%2d%2d%2d", &Time.hh, &Time.mm, &Time.ss);
563 sprintf(accept_s, "%02d%02d%02d", Time.hh, Time.mm, Time.ss);
564 if (is_valid_time(Time.hh, Time.mm, Time.ss))
565 sprintf(display_s, "%02d:%02d:%02d", Time.hh, Time.mm, Time.ss);
566 break;
567 case FF_APR:
568 sscanf(input_s, "%lf", &double_n);
569 sprintf(accept_s, "%lf", double_n);
570 sprintf(display_s, "%0.3lf", double_n);
571 right_justify(display_s, fl);
572 break;
573 default:
574 Perror("form_fmt_field() invalid format");
575 break;
576 }
577 strnz(accept_s, fl);
578 left_justify(accept_s);
579 mk_filler(filler_s, fl);
580 return 0;
581}
582/** @brief Validate current field based on flags
583 @ingroup fields
584 @param form Pointer to Form structure
585 @return 0 if valid, 1 if invalid
586 @note Very underdeveloped - only checks F_NOTBLANK and F_NOMETAS
587 */
588int form_validate_field(Form *form) {
589 int n = form->fidx;
590 char *p = form->field[n]->accept_s;
591 if (form->field[n]->ff & F_NOTBLANK) {
592 char *s = form->field[n]->accept_s;
593 while (*s++ == ' ')
594 ;
595 if (*s == '\0') {
596 Perror("blank field not allowed");
597 return (1);
598 }
599 }
600 if (form->field[n]->ff & F_NOMETAS) {
601 if (strpbrk(p, "*?[]") != 0) {
602 Perror("metacharacters not allowed");
603 return (1);
604 }
605 }
606 return (0);
607}
608/** @brief Create filler string for field
609 @ingroup fields
610 @param s Filler string to create
611 @param fl Field length
612 @note Fills the string s with the fill character specified in the form's
613 fill_char array, repeated for the length of the field (fl). The resulting
614 string is null-terminated. This filler string can be used to display empty
615 fields or to clear the field area before displaying new content.
616 */
617void mk_filler(char *s, int fl) {
618 char *e = s + fl;
619 unsigned char c;
620
621 c = form->fill_char[0];
622 while (s != e)
623 *s++ = c;
624 *s = '\0';
625}
626/** @brief Left justify string by removing leading spaces
627 @ingroup fields
628 @param s String to left justify
629 @note This function takes a string s and removes any leading spaces,
630 effectively left-justifying the text. It does this by finding the first
631 non-space character and shifting the string to the left, overwriting the
632 leading spaces. The resulting string is null-terminated.
633 */
634void left_justify(char *s) { trim(s); }
635/** @brief Right justify string by removing trailing spaces and adding leading
636 @ingroup fields
637 spaces
638 @param s String to right justify
639 @param fl Field length
640 @note This function takes a string s and right-justifies it within a field
641 of length fl. It first removes any trailing spaces from the string, then
642 shifts the characters to the right end of the field, filling the left side
643 with spaces. The resulting string is null-terminated and fits within the
644 specified field length.
645 */
646void right_justify(char *s, int fl) {
647 char *p = s;
648 char *d = s + fl;
649 trim(s);
650 *d = '\0';
651 while (*s != '\0') {
652 s++;
653 }
654 while (s != p) {
655 *(--d) = *(--s);
656 }
657 while (d != p) {
658 *(--d) = ' ';
659 }
660}
661/** @brief Check if a given date is valid, including leap years
662 @ingroup fields
663 @param yyyy Year
664 @param mm Month
665 @param dd Day
666 @return true if the date is valid, false otherwise
667 @note This function checks if the provided year, month, and day constitute a
668 valid date. It accounts for leap years when determining the number of days in
669 February. The function returns true if the date is valid and false if it is
670 not.
671 */
672bool is_valid_date(int yyyy, int mm, int dd) {
673 if (yyyy < 1 || mm < 1 || mm > 12 || dd < 1)
674 return false;
675 int days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
676 if ((yyyy % 4 == 0 && yyyy % 100 != 0) || (yyyy % 400 == 0))
677 days_in_month[2] = 29;
678 if (dd > days_in_month[mm])
679 return false;
680 return true;
681}
682/** @brief Check if a given time is valid
683 @ingroup fields
684 @param hh Hour
685 @param mm Minute
686 @param ss Second
687 @return true if the time is valid, false otherwise
688 @note This function checks if the provided hour, minute, and second
689 constitute a valid time. It ensures that hours are between 0 and 23, minutes
690 and seconds are between 0 and 59. The function returns true if the time is
691 valid and false if it is not.
692 */
693bool is_valid_time(int hh, int mm, int ss) {
694 if (hh < 0 || hh > 23 || mm < 0 || mm > 59 || ss < 0 || ss > 59)
695 return false;
696 return true;
697}
698/** @brief Extract numeric characters from source string to destination string
699 @ingroup fields
700 @param d Destination string
701 @param s Source string
702 @note This function takes a source string s and extracts only the numeric
703 characters (digits 0-9), as well as dashes ('-') and periods ('.'), copying
704 them into the destination string d. The resulting string in d is
705 null-terminated. This is useful for processing input that may contain
706 non-numeric characters, allowing the application to focus on the numeric
707 content for further processing or validation.
708 */
709void numeric(char *d, char *s) {
710 while (*s != '\0') {
711 if (*s == '-' || *s == '.' || (*s >= '0' && *s <= '9'))
712 *d++ = *s++;
713 else
714 s++;
715 }
716 *d = '\0';
717}
int form_yx_to_fidx(Form *, int, int)
#define FIELD_MAXLEN
Definition form.h:18
@ FF_DECIMAL_INT
Definition form.h:51
@ FF_STRING
Definition form.h:49
@ FF_HEX_INT
Definition form.h:53
@ FF_YYYYMMDD
Definition form.h:62
@ FF_HHMMSS
Definition form.h:64
@ FF_CURRENCY
Definition form.h:59
@ FF_FLOAT
Definition form.h:55
@ FF_DOUBLE
Definition form.h:57
@ FF_APR
Definition form.h:66
#define F_NOTBLANK
Definition form.h:21
Form * form
Definition mem.c:47
#define F_NOMETAS
Definition form.h:20
#define min(x, y)
min macro evaluates two expressions, returning least result
Definition cm.h:55
#define Ctrl(c)
Definition cm.h:33
#define TRUE
Definition iloan.c:19
#define FALSE
Definition iloan.c:18
void display_chyron(WINDOW *win, Chyron *chyron, int line, int col)
Definition dwin.c:297
int click_x
Definition dwin.c:45
int click_y
Definition dwin.c:44
int cp_reverse_highlight
Definition dwin.c:140
int cp_reverse
Definition dwin.c:139
char ff_tbl[][26]
Definition fields.c:40
int xwgetch(WINDOW *, Chyron *, int)
Wrapper for wgetch that handles signals, mouse events, checks for clicks on the chyron line,...
Definition dwin.c:1359
void set_chyron_key_cp(Chyron *, int, char *, int, int)
Set chyron key.
Definition dwin.c:237
void compile_chyron(Chyron *)
construct the chyron string from the chyron structure
Definition dwin.c:268
int Perror(char *)
Display a simple error message window or print to stderr.
Definition dwin.c:1110
int form_fmt_field(Form *, char *)
Format field according to its format type.
Definition fields.c:421
int field_editor(Form *)
Accept input for a field.
Definition fields.c:59
void numeric(char *, char *)
Extract numeric characters from source string to destination string.
Definition fields.c:709
void right_justify(char *, int)
Right justify string by removing trailing spaces and adding leadingspaces.
Definition fields.c:646
bool is_valid_date(int, int, int)
Check if a given date is valid, including leap years.
Definition fields.c:672
void left_justify(char *)
Left justify string by removing leading spaces.
Definition fields.c:634
bool is_valid_time(int, int, int)
Check if a given time is valid.
Definition fields.c:693
int form_display_field_n(Form *, int)
Display field n.
Definition fields.c:351
void mk_filler(char *, int)
Create filler string for field.
Definition fields.c:617
int form_display_field(Form *)
Display current field.
Definition fields.c:369
int form_validate_field(Form *)
Validate current field based on flags.
Definition fields.c:588
int form_display_field_brackets(Form *)
Display brackets around current field if set.
Definition fields.c:389
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition futil.c:269
size_t trim(char *)
Trims leading and trailing spaces from string s in place.
Definition futil.c:118
size_t strnz(char *, size_t)
terminates string at New Line, Carriage Return, or max_len
Definition futil.c:340
int l
Definition cm.h:244
int line
Definition form.h:115
char display_s[FIELD_MAXLEN]
Definition form.h:132
char accept_s[FIELD_MAXLEN]
Definition form.h:128
int ff
Definition form.h:121
int col
Definition form.h:117
char input_s[FIELD_MAXLEN]
Definition form.h:125
int len
Definition form.h:119
char filler_s[FIELD_MAXLEN]
Definition form.h:137
bool f_erase_remainder
Definition form.h:235
WINDOW * box
Definition form.h:156
Field * field[FIELD_MAXCNT]
Definition form.h:344
int lines
Definition form.h:149
int fidx
Definition form.h:301
char fill_char[2]
Definition form.h:290
Chyron * chyron
Definition form.h:356
char brackets[3]
Definition form.h:278
WINDOW * win
Definition form.h:155