C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
form_engine.c
Go to the documentation of this file.
1/** @file form_engine.c
2 @brief The working part of 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// #define DEBUG_IMMEDOK true
10/** @defgroup form_engine Form Engine
11 @brief Parses Form Descriptions, Handles User Input, and Integrates with
12 External Commands for Calculations and Data Processing.
13 */
14
15#include <common.h>
16#include <errno.h>
17#include <fcntl.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/stat.h>
21#include <termios.h>
22#include <unistd.h>
23#include <wait.h>
24
25#define D_COMMENT '#'
26#define D_CMD '!'
27#define D_FIELD 'F'
28#define D_TEXT 'T'
29#define D_HELP '?'
30#define D_HEADER 'H'
31#define D_CALC 'C'
32#define D_QUERY 'Q'
33#define D_GETTER 'G'
34
35unsigned int display_form(Init *);
36void form_display_fields(Form *);
37int field_navigator(Form *);
38int form_parse_desc(Form *);
39int form_read_data(Form *);
40int form_write(Form *);
42int form_desc_error(Form *form, int, char *, char *);
43int form_exec_cmd(Form *);
44int form_exec_receiver(Init *);
45int form_process(Init *);
46int form_post(Init *);
47int init_form(Init *, int, char **, int, int);
48int form_engine(Init *);
49int form_yx_to_fidx(Form *, int, int);
50void mk_filler(char *, int);
51
52/** @brief Initialize form data structure and parse description file
53 @ingroup form_engine
54 @param init A pointer to the Init structure containing form data and state.
55 @param argc The number of command line arguments passed to the form.
56 @param argv The array of command line arguments passed to the form.
57 @param begy The y-coordinate for the top-left corner of the form window.
58 @param begx The x-coordinate for the top-left corner of the form window.
59 @return 0 on success, or a non-zero value if an error occurs during
60*/
61int init_form(Init *init, int argc, char **argv, int begy, int begx) {
62 int rc;
63 char tmp_str[MAXLEN];
64 if (init->form != nullptr)
66 init->form = new_form(init, argc, argv, begy, begx);
67 Form *form = init->form;
68 if (!form->f_mapp_spec) {
69 if (form->mapp_spec[0] == '\0') {
70 rc = Perror("Error: No form specification file given");
71 } else {
72 strnz__cpy(tmp_str, "form->mapp_spec: ", MAXLEN - 1);
73 strnz__cat(tmp_str, form->mapp_spec, MAXLEN - 1);
74 strnz__cat(tmp_str, " not found", MAXLEN - 1);
75 rc = Perror(tmp_str);
76 }
78 return rc;
79 }
80 if (begy != 0)
81 form->begy = begy;
82 if (begx != 0)
83 form->begx = begx;
84 if ((form->f_in_spec && (form->in_spec[0] == '\0')) ||
85 (strcmp(form->in_spec, "-") == 0) ||
86 strcmp(form->in_spec, "/dev/stdin") == 0) {
87 strnz__cpy(form->in_spec, "/dev/stdin", MAXLEN - 1);
88 form->f_in_pipe = true;
89 }
90 if (form->title[0] == '\0')
92 form->brktl = mkcc(cp_brackets, WA_NORMAL, &form->brackets[0]);
93 form->brktr = mkcc(cp_brackets, WA_NORMAL, &form->brackets[1]);
94
95 rc = form_engine(init);
97 if (form->win)
100 return rc;
101}
102/** @brief Form main processing loop
103 @ingroup form_engine
104 @param init A pointer to the Init structure containing form data and state.
105 @return 0 on successful completion, or a non-zero value if the user cancels
106 the form or if an error occurs during processing.
107 1. Parse the form description file to populate the form data structure.
108 2. Read any initial data for the form fields from a specified input
109 source.
110 3. Display the form on the screen with the initial field values.
111 4. Enter a loop to handle user input for field entry, calculation, help,
112 and cancellation:
113 a. If the user selects the accept action, perform any necessary
114 calculations or post-processing, and then either return to field entry
115 or exit the loop if the form is accepted.
116 b. If the user selects the help action, display the help screen and
117 return to the form after the user exits the help screen.
118 c. If the user selects the cancel action, exit the loop and return a
119 cancel status. */
120int form_engine(Init *init) {
121 char tmp_str[MAXLEN];
122 int form_action;
123 char *eargv[MAXARGS];
124 int eargc;
125
126 Form *form = init->form;
127 if (form == nullptr) {
128 Perror("FORM: form data structure is nullptr");
129 }
130 if (form_parse_desc(form)) {
131 return 0;
132 }
133
135 display_form(init);
137 set_chyron_key(form->chyron, 1, "F1 Help", KEY_F(1));
138 set_chyron_key_cp(form->chyron, 2, "F2 Process", KEY_F(2), cp_nt_hl_rev);
139 set_chyron_key_cp(form->chyron, 3, "F3 Calculate", KEY_F(3), cp_nt_hl_rev);
140 set_chyron_key_cp(form->chyron, 4, "F4 Query", KEY_F(4), cp_nt_hl_rev);
141 set_chyron_key_cp(form->chyron, 5, "F5 Edit", KEY_F(5), cp_nt_hl_rev);
142 set_chyron_key(form->chyron, 9, "F9 Cancel", KEY_F(9));
143 set_chyron_key(form->chyron, 10, "F10 Accept", KEY_F(10));
144 set_chyron_key(form->chyron, 18, "INS", KEY_IC);
145 form->chyron->key[2]->active = false; // F2 Process
146 form->chyron->key[3]->active = false; // F3 Calculate
147 form->chyron->key[4]->active = false; // F4 Query
148 form->chyron->key[5]->active = false; // F5 Edit
149 form->chyron->key[18]->active = false; // Insert
152 // 1 F1 Help
153 // 2 F2 Process
154 // 3 F3 Calculate
155 // 4 F4 Query
156 // 5 F5 Edit
157 // 9 F9 Cancel
158 // 10 F10 Accept
159 form->fidx = 0;
160 form_action = 0;
161 while (1) {
162 if (form_action == 0 || form_action == FA_CONTINUE)
163 form_action = field_navigator(form);
164 form->chyron->key[18]->active = false; // Insert
165 switch (form_action) {
166 case FA_ACCEPT:
167 if (form->f_process || form->f_calculate || form->f_query)
168 form_action = form_process(init);
169 else
170 form_action = form_post(init);
171 if (form_action == FA_HELP || form_action == FA_CANCEL ||
172 form_action == FA_CONTINUE || form_action == FA_END)
173 continue;
174 if (form_action == FA_ACCEPT) {
175 form_action = FA_END;
176 continue;
177 }
178 break;
179 case FA_END:
180 if (form->f_out_spec || form->out_spec[0] != '\0')
181 form_write(form);
182 if (form->f_receiver_cmd || form->receiver_cmd[0] != '\0')
184 break;
185 case FA_HELP:
186 if (form->f_help_spec && form->help_spec[0] != '\0')
187 strnz__cpy(tmp_str, form->help_spec, MAXLEN - 1);
188 else {
189 strnz__cpy(tmp_str, init->mapp_help, MAXLEN - 1);
190 strnz__cat(tmp_str, "/", MAXLEN - 1);
192 }
193 eargc = 0;
194 eargv[eargc++] = strdup("view");
195 eargv[eargc++] = strdup("-Nf");
196 eargv[eargc++] = strdup(tmp_str);
197 eargv[eargc] = nullptr;
198 init->lines = 30;
199 init->cols = 66;
200 init->begy = form->begy + 1;
201 init->begx = form->begx + 1;
202 strnz__cpy(init->title, "Form Help", MAXLEN - 1);
203 popup_view(init, eargc, eargv, init->lines, init->cols, init->begy,
204 init->begx);
205 destroy_argv(eargc, eargv);
206 form_action = FA_CONTINUE;
207 break;
208 case FA_CANCEL:
209 return FA_CANCEL;
210 default:
211 form_action = FA_CONTINUE;
212 break;
213 }
214 if (form_action == FA_END)
215 break;
216 }
217 return 0;
218}
219/** @brief Handle post-processing after field entry, allowing user to edit data,
220 execute a provider command, or write data to an output file.
221 @ingroup form_engine
222 @param init A pointer to the Init structure containing form data and state.
223 @return An integer status code indicating the next action for the form
224 processing loop (e.g., FA_CONTINUE, FA_CANCEL, FA_ACCEPT, FA_HELP). */
225int form_post(Init *init) {
226 bool loop = true;
227 int c, rc;
228 click_y = click_x = -1;
229 Form *form = init->form;
230 wmove(form->win, form->lines - 1, 0);
231 wclrtoeol(form->win);
232 // 1 F1 Help
233 // 2 F2 Process
234 // 3 F3 Calculate
235 // 4 F4 Query
236 // 5 F5 Edit
237 // 9 F9 Cancel
238 // 10 F10 Continue
239 // 11 F10 Commit
240 // 18 INS Insert
241 form->chyron->key[5]->active = true; // F5 Edit
242 form->chyron->key[10]->active = false; // F10 Continue
243 form->chyron->key[18]->active = false; // INS Insert
245 rc = -1;
246 while (loop) {
247 if (rc == -1) {
249 form->chyron->l);
250 tcflush(2, TCIFLUSH);
251 update_panels();
252 doupdate();
253 c = xwgetch(form->win, form->chyron, -1);
254 }
255 switch (c) {
256 case KEY_F(1):
257 return FA_HELP;
258 case KEY_F(5): // F5 Edit
260 loop = false;
261 rc = FA_CONTINUE;
262 break;
263 }
264 continue;
265 case KEY_F(9):
266 loop = false;
267 rc = FA_CANCEL;
268 break;
269 case KEY_F(10):
270 loop = false;
271 rc = FA_ACCEPT;
272 break;
273 case KEY_MOUSE:
274 continue;
275 default:
276 break;
277 }
278 }
279 form->chyron->key[5]->active = false; // F5 Edit
280 return rc;
281}
282
283/** @brief Handle integration with a getter program which will provide field
284 data.
285 @ingroup form_engine
286 @param init A pointer to the Init structure containing form data and state.
287 @return An integer status code indicating the next action for the form
288 processing loop (e.g., FA_CONTINUE, FA_CANCEL, FA_ACCEPT, FA_HELP).
289 @details This function provides integration with getter programs.
290 The requirements are:
291 1. The form description file must have a line containing only 'C'
292 (calculate), 'Q' (query), org 'G' (getter) to indicate that the form supports
293 a getter.
294 2. The form description file must specify the provider command using a
295 line starting with '!' followed by the command and its arguments.
296 3. The getter program must be able to accept field data from a file,
297 from standard input, or as command line parameters.
298 4. The getter program must output field values in a format that can be
299 read by the form (e.g., one value per line), either to a file or to standard
300 output.
301
302 The sequence of operations is as follows:
303
304 1. The 'C', 'Q', or 'G' option causes Form to pause and display an
305 KEY_F(5) Calculate, Query, or Getter. option on the chyron.
306 2. The user can then cancel the operation by pressing KEY_F(9) or
307 activate the getter option by pressing KEY_F(5).
308 3. Form outputs its data to file, standard output, or as command line
309 parameters.
310 4. Form executes the getter program.
311 5. The getter program processes the data and outputs the results.
312 6. Form reads the results and populates the appropriate form fields.
313 7. Form presents the user with an option to edit the data, and the
314 sequence restarts at 1.
315
316 This function forks and executes the getter executable as a child
317 process, creates a pipe to read the output from the provider command,
318 reads the output, and updates the Form fields.
319 */
320int form_process(Init *init) {
321 int i, c, rc;
322 char earg_str[MAXLEN + 1];
323 char *eargv[MAXARGS];
324 int eargc;
325 char file_spec[MAXLEN];
326 bool loop = true;
327 pid_t pid;
328 int pipe_fd[2];
329
330 Form *form = init->form;
331 wmove(form->win, form->lines - 1, 0);
332 //
333 // 1 F1 Help
334 // 2 F2 Process
335 // 3 F3 Calculate
336 // 4 F4 Query
337 // 5 F5 Edit
338 // 9 F9 Cancel
339 // 10 F10 Continue
340 // 11 F10 Commit
341 form->chyron->key[2]->active = form->f_process > 0 ? true : false;
342 form->chyron->key[3]->active = form->f_calculate > 0 ? true : false;
343 form->chyron->key[4]->active = form->f_query > 0 ? true : false; // PgUp
344 form->chyron->key[10]->active = false; // F10 Continue
345 form->chyron->key[18]->active = false; // INS Insert
346
347 while (loop) {
350 form->chyron->l);
351 click_y = click_x = -1;
352 tcflush(2, TCIFLUSH);
353 update_panels();
354 doupdate();
355 c = xwgetch(form->win, form->chyron, -1);
356 switch (c) {
357 case KEY_F(1):
358 return FA_HELP;
359 case KEY_F(2): // F2 Process
360 case KEY_F(3): // F3 Calculate
361 case KEY_F(4): // F4 Query
362 if (form->f_out_spec)
363 form_write(form);
364 if (form->f_provider_cmd) {
365 strnz__cpy(earg_str, form->provider_cmd, MAXLEN - 1);
366 for (i = 0; i < form->fcnt; i++) {
367 strnz__cat(earg_str, " ", MAXLEN - 1);
368 strnz__cat(earg_str, form->field[i]->accept_s, MAXLEN - 1);
369 }
370 eargc = str_to_args(eargv, earg_str, MAXARGS);
371 strnz__cpy(file_spec, eargv[0], MAXLEN - 1);
372 base_name(eargv[0], file_spec);
373 if (pipe(pipe_fd) == -1) {
374 destroy_argv(eargc, eargv);
375 Perror("pipe(pipe_fd) failed in init_form");
376 return (1);
377 }
378 if ((pid = fork()) == -1) {
379 destroy_argv(eargc, eargv);
380 Perror("fork() failed in init_form");
381 return (1);
382 }
383 if (pid == 0) { // Child
384 /** Prevent child process from writing to terminal */
385 int dev_null = open("/dev/null", O_WRONLY);
386 if (dev_null == -1) {
387 Perror("open(/dev/null) failed in init_pick child "
388 "process");
389 exit(EXIT_FAILURE);
390 }
391 dup2(dev_null, STDERR_FILENO);
392 close(dev_null);
393 close(pipe_fd[P_READ]);
394 dup2(pipe_fd[P_WRITE], STDOUT_FILENO);
395 stdio_fdnames(stdio_names_str, "form_engine.c:367");
396 close(pipe_fd[P_WRITE]);
397 execvp(eargv[0], eargv);
398 ssnprintf(em0, MAXLEN, "%s, line: %d", __FILE__,
399 __LINE__ - 2);
400 strnz__cpy(em1, "execvp(", MAXLEN - 1);
401 strnz__cat(em1, eargv[0], MAXLEN - 1);
402 strnz__cat(em1, ", ", MAXLEN - 1);
403 strnz__cat(em1, earg_str, MAXLEN - 1);
405 strerror_r(errno, em2, MAXLEN);
407 exit(EXIT_FAILURE);
408 } // Back to parent
409 close(pipe_fd[P_WRITE]);
410 form->in_fp = fdopen(pipe_fd[P_READ], "rb");
411 form->f_in_pipe = true;
413 close(pipe_fd[P_READ]);
415 stdio_fdnames(stdio_names_str, "form_engine.c:387");
416 destroy_argv(eargc, eargv);
418 form->chyron->key[2]->active = false; // F2 Process
419 form->chyron->key[3]->active = false; // F3 Calculate
420 form->chyron->key[4]->active = false; // F4 Query
421 form->chyron->key[5]->active = true; // F5 Edit
422 form->chyron->key[10]->active = true; // F10 Accept
424 continue;
425 }
426 break;
427 case KEY_F(5):
429 loop = false;
430 rc = FA_CONTINUE;
431 break;
432 }
433 continue;
434 case KEY_F(9):
435 loop = false;
436 rc = FA_CANCEL;
437 break;
438 case KEY_F(10):
439 loop = false;
440 rc = FA_ACCEPT;
441 break;
442 case KEY_MOUSE:
443 break;
444 default:
445 break;
446 }
447 }
448 form->chyron->key[2]->active = false; // F2 Process
449 form->chyron->key[3]->active = false; // F3 Calculate
450 form->chyron->key[4]->active = false; // F4 Query
451 form->chyron->key[5]->active = false; // F5 Edit
452 return rc;
453}
454/** @brief Handle user input for field entry, allowing navigation between fields
455 and looping until an exit action is selected.
456 @ingroup form_engine
457 @param form A pointer to the Form structure containing form data and state.
458 @return An integer status code indicating the next action for the form
459 processing loop (e.g., FA_ACCEPT, FA_HELP, FA_CALC, FA_CANCEL).
460 @details This function manages user input for field entry, including
461 navigation between fields and handling of special keys for accepting,
462 canceling, requesting help, or performing calculations. The function loops
463 until the user selects an exit action (e.g., accept or cancel). */
464int field_navigator(Form *form) {
465
466 if (form->fidx < 0 || form->fidx >= form->fcnt)
467 form->fidx = 0;
468 while (1) {
469 int cmd_key = field_editor(form);
470 switch (cmd_key) {
471 case KEY_F(1): // F1 Help
472 return (FA_HELP);
473 case KEY_F(2): // F2 Process
474 case KEY_F(3): // F3 Calculate
475 case KEY_F(4): // F4 Query
476 if (form->f_process)
477 return (FA_CALC);
478 break;
479 case KEY_F(9): // F9 Cancel
480 return (FA_CANCEL);
481 case KEY_F(10): // F10 Accept
482 return (FA_ACCEPT);
483 case 'k':
484 case KEY_UP:
485 if (form->fidx != 0)
486 form->fidx--;
487 break;
488 case '\r':
489 case KEY_ENTER:
490 if (form->fidx < form->fcnt - 1)
491 form->fidx++;
492 else if (form->fidx == form->fcnt - 1)
493 return (FA_ACCEPT);
494 break;
495 case 'j':
496 case KEY_DOWN:
497 if (form->fidx < form->fcnt - 1)
498 form->fidx++;
499 else if (form->fidx == form->fcnt - 1)
500 return (FA_ACCEPT);
501 break;
502 case KEY_MOUSE:
503 break;
504 default:
505 break;
506 }
507 }
508}
509int form_yx_to_fidx(Form *form, int y, int x) {
510 for (int i = 0; i < form->fcnt; i++) {
511 if (y == form->field[i]->line && x >= form->field[i]->col &&
512 x < form->field[i]->col + form->field[i]->len) {
513 return i;
514 }
515 }
516 return -1; // No field found at the given coordinates
517}
518
519/** @brief Display the form on the screen, including text elements and fields,
520 and set up the form window based on the form configuration.
521 @ingroup form_engine
522 @param init A pointer to the Init structure containing form data and state.
523 @return 0 on success, or a non-zero value if an error occurs while
524 creating the form window or rendering the form elements. */
525unsigned int display_form(Init *init) {
526 int n, flin, fcol;
527 char tmp_str[MAXLEN];
528
529 Form *form = init->form;
530 form->lines = 0;
531 for (n = 0; n < form->dcnt; n++)
532 if (form->text[n]->line > form->lines)
533 form->lines = form->text[n]->line;
534 for (n = 0; n < form->fcnt; n++)
535 if (form->field[n]->line > form->lines)
536 form->lines = form->field[n]->line;
537 form->lines += 3;
538 if (form->lines > (LINES - form->begy))
539 form->lines = LINES - form->begy;
540 for (n = 0; n < form->fcnt; n++) {
541 if (form->field[n]->line >= (form->lines - 2))
542 form->fcnt = n;
543 }
544 form->cols += 2;
545 if (form->cols > (COLS - form->begx - 3))
546 form->cols = COLS - form->begx - 3;
547 if (box_new(form->lines, form->cols, form->begy, form->begx, form->title)) {
548 strnz__cpy(tmp_str, "box_new failed: ", MAXLEN - 1);
549 strnz__cat(tmp_str, form->title, MAXLEN - 1);
550 Perror(tmp_str);
551 return (1);
552 }
553 form->box = win_box[win_ptr];
554 form->win = win_win[win_ptr];
555#ifdef DEBUG_IMMEDOK
556 immedok(form->win, true);
557 immedok(form->box, true);
558#endif
559 // wnoutrefresh(form->win);
560 // display field brackets if specified in the form description
561 for (form->fidx = 0; form->fidx < form->fcnt; form->fidx++) {
562 if (form->brackets[0] != '\0' && form->brackets[1] != '\0') {
563 flin = form->field[form->fidx]->line + 1;
564 fcol = form->field[form->fidx]->col;
565 mvwadd_wch(form->box, flin, fcol, &form->brktl);
566 fcol += form->field[form->fidx]->len + 1;
567 mvwadd_wch(form->box, flin, fcol, &form->brktr);
568 // wnoutrefresh(form->box);
569 }
570 }
571 for (n = 0; n < form->dcnt; n++) {
572 strnz(form->text[n]->str, form->cols - 3);
573 mvwaddstr(form->win, form->text[n]->line, form->text[n]->col,
574 form->text[n]->str);
575 // wnoutrefresh(form->win);
576 }
577 update_panels();
579 return 0;
580}
581/** @brief Display form fields on the screen, populating field values and
582 formatting them according to the form configuration.
583 @ingroup form_engine
584 @param form A pointer to the Form structure containing form data and
585 state.
586 @details This function iterates through the defined form fields, formats
587 their display values based on the specified fill character and field
588 length, and renders them on the form window. It also updates the chyron
589 with available commands for user interaction. */
590void form_display_fields(Form *form) {
591 int y, x;
592 for (form->fidx = 0; form->fidx < form->fcnt; form->fidx++) {
593 if (form->field[form->fidx]->col + form->field[form->fidx]->len + 2 >
594 form->cols)
595 form->field[form->fidx]->len =
596 form->cols - (form->field[form->fidx]->col + 2);
597 // Make filler_cc
598 size_t fl = form->field[form->fidx]->len;
599 char *d = form->field[form->fidx]->filler_s;
600 size_t char_bytes = strlen(form->fill_char);
601 for (size_t i = 0; i < fl; i++) {
602 memcpy(d, form->fill_char, char_bytes);
603 d += char_bytes;
604 }
605 d = nullptr;
606
607 if (form->field[form->fidx]->accept_s[0] != '\0') {
609 // d = form->field[form->fidx]->accept_s;
610 } else {
611 memset(form->field[form->fidx]->accept_s, 0, MAXLEN);
612 // d = form->field[form->fidx]->accept_s;
613 }
615
616 y = form->field[form->fidx]->line;
617 x = form->field[form->fidx]->col;
618
620
621 mvwadd_wchstr(form->win, y, x, form->field[form->fidx]->filler_cc);
622
624
625 mvwadd_wchnstr(form->win, y, x, form->field[form->fidx]->display_cc, form->field[form->fidx]->len);
626 update_panels();
627 doupdate();
628 }
629 return;
630}
631/** @brief Parse the form description file to populate the Form data
632 structure with field definitions, text elements, and other configuration
633 specified in the description file.
634 @ingroup form_engine
635 @param form A pointer to the Form structure containing form data and
636 state.
637 @return 0 on success, or a non-zero value if an error occurs while
638 parsing the description file (e.g., file not found, invalid format,
639 missing directives). */
640int form_parse_desc(Form *form) {
641 FILE *form_desc_fp;
642 char *token;
643 char *s;
644 int cols = 0;
645 int i, l;
646 int in_line_num = 0;
647 char in_buf[BUFSIZ];
648 char tmp_buf[BUFSIZ];
649 char *tmp_buf_p;
650 char tmp_str[BUFSIZ];
651 char delim[5];
652 char directive;
653
654 form_desc_fp = fopen(form->mapp_spec, "r");
655 if (form_desc_fp == nullptr) {
656 ssnprintf(em0, MAXLEN - 1, "%s, line: %d", __FILE__, __LINE__ - 2);
657 strnz__cpy(em1, "fopen ", MAXLEN - 1);
659 strerror_r(errno, em2, MAXLEN);
661 return (1);
662 }
663 for (i = 0; i < FIELD_MAXCNT; i++) {
664 form->field[i] = calloc(1, sizeof(Field));
665 if (!form->field[i]) {
666 sprintf(tmp_str, "FORM: calloc failed for fields");
667 abend(EXIT_FAILURE, tmp_str);
668 }
669 }
670 for (i = 0; i < FIELD_MAXCNT; i++) {
671 form->text[i] = calloc(1, sizeof(Text));
672 if (!form->text[i]) {
673 sprintf(tmp_str, "FORM: calloc failed for text");
674 abend(EXIT_FAILURE, tmp_str);
675 }
676 }
677 form->didx = 0;
678 form->fidx = 0;
679 form->fcnt = 0;
680 form->cols = 34;
681 while ((fgets(in_buf, MAXLEN, form_desc_fp)) != nullptr) {
682 s = in_buf;
683 in_line_num++;
684 l = trim(in_buf);
685 if (l == 0)
686 continue;
687 if (*s == D_COMMENT)
688 continue;
689 delim[0] = '\n';
690 delim[1] = in_buf[1];
691 delim[2] = '\0';
692 strnz__cpy(tmp_buf, in_buf, MAXLEN - 1);
693 tmp_buf_p = tmp_buf;
694 if (!(token = strtok(tmp_buf_p, delim))) {
695 continue;
696 }
697 directive = *token;
698 switch ((int)directive) {
699 case D_COMMENT:
700 break;
701 case D_CALC:
702 form->f_calculate = true;
703 break;
704 case D_QUERY:
705 form->f_query = true;
706 break;
707 case D_GETTER:
708 form->f_process = true;
709 break;
710 case D_CMD:
711 if (!(token = strtok(nullptr, delim))) {
712 form_desc_error(form, in_line_num, in_buf,
713 "FORM: receiver_cmd delimiter");
714 continue;
715 }
717 break;
718 case D_HELP:
719 if (!(token = strtok(nullptr, delim))) {
720 form_desc_error(form, in_line_num, in_buf,
721 "FORM: help_spec delimiter");
722 }
723 strnz__cpy(form->help_spec, token, MAXLEN - 1);
724 break;
725 case D_FIELD:
726 if (form->field[form->fidx] == nullptr) {
727 sprintf(tmp_str, "FORM: calloc failed for fields");
728 abend(EXIT_FAILURE, tmp_str);
729 }
730 if (!(token = strtok(nullptr, delim))) {
731 form_desc_error(form, in_line_num, in_buf,
732 "FORM: line number delimiter");
733 return 1;
734 }
735 form->field[form->fidx]->line = atoi(token);
736 if (form->field[form->fidx]->line < 0 ||
737 form->field[form->fidx]->line >= FIELD_MAXCNT) {
738 form_desc_error(form, in_line_num, in_buf,
739 "FORM: invalid line number");
740 return 1;
741 }
742 if (!(token = strtok(nullptr, delim))) {
743 form_desc_error(form, in_line_num, in_buf,
744 "FORM: column number delimiter");
745 return 1;
746 }
747 form->field[form->fidx]->col = atoi(token);
748 if (form->field[form->fidx]->col < 0 ||
749 form->field[form->fidx]->col >= FIELD_MAXLEN) {
750 form_desc_error(form, in_line_num, in_buf,
751 "FORM: invalid column number");
752 break;
753 }
754 if (!(token = strtok(nullptr, delim))) {
755 strnz__cpy(tmp_str, in_buf, MAXLEN - 1);
756 form_desc_error(form, in_line_num, tmp_str, "FORM: length delimiter");
757 break;
758 }
759 form->field[form->fidx]->len = atoi(token);
760 if (form->field[form->fidx]->len < 0 ||
761 form->field[form->fidx]->len > FIELD_MAXLEN) {
762 form_desc_error(form, in_line_num, in_buf, "FORM: invalid length");
763 break;
764 }
765 if (!(token = strtok(nullptr, delim))) {
766 form_desc_error(form, in_line_num, in_buf,
767 "FORM: validation code delimiter");
768 break;
769 }
770 form->field[form->fidx]->ff = -1;
771 for (i = 0; i < FF_INVALID; i++) {
772 str_to_lower(token);
774 if (!strcmp(token, ff_tbl[i])) {
775 form->field[form->fidx]->ff = i;
776 break;
777 }
778 }
779 if (form->field[form->fidx]->ff < 0 ||
780 form->field[form->fidx]->ff >= FF_INVALID) {
781 form_desc_error(form, in_line_num, in_buf,
782 "FORM: invalid format code");
783 break;
784 }
785 cols =
786 form->field[form->fidx]->col + form->field[form->fidx]->len + 1;
787 if (cols > form->cols)
788 form->cols = cols;
789 form->fidx++;
790 form->fcnt = form->fidx;
791 break;
792 case D_TEXT:
793 if (form->text[form->didx] == nullptr) {
794 sprintf(tmp_str, "FORM: calloc failed for text");
795 abend(EXIT_FAILURE, tmp_str);
796 }
797 if (!(token = strtok(nullptr, delim))) {
798 form_desc_error(form, in_line_num, in_buf,
799 "FORM: line number delimiter");
800 break;
801 }
802 form->text[form->didx]->line = atoi(token);
803 if (form->text[form->didx]->line < 0 ||
804 form->text[form->didx]->line >= FIELD_MAXCNT) {
805 form_desc_error(form, in_line_num, in_buf,
806 "FORM: invalid line number");
807 break;
808 }
809 if (!(token = strtok(nullptr, delim))) {
810 form_desc_error(form, in_line_num, in_buf,
811 "FORM: column number delimiter");
812 break;
813 }
814 form->text[form->didx]->col = atoi(token);
815 if (form->text[form->didx]->col < 0 ||
816 form->text[form->didx]->col >= FIELD_MAXLEN) {
817 form_desc_error(form, in_line_num, in_buf,
818 "FORM: invalid column number");
819 break;
820 }
821 if (!(token = strtok(nullptr, delim))) {
822 form_desc_error(form, in_line_num, in_buf, "FORM: text delimiter");
823 break;
824 }
825 strnz__cpy(form->text[form->didx]->str, token, MAXLEN - 1);
826 form->text[form->didx]->len = strlen(form->text[form->didx]->str);
827 if (form->text[form->didx]->len < 0 ||
828 form->text[form->didx]->len > FIELD_MAXLEN) {
829 form_desc_error(form, in_line_num, in_buf, "FORM: invalid length");
830 break;
831 }
832 cols =
833 form->text[form->didx]->col + form->text[form->didx]->len + 1;
834 if (cols > form->cols)
835 form->cols = cols;
836 form->didx++;
837 form->dcnt = form->didx;
838 break;
839 case D_HEADER:
840 if ((token = strtok(nullptr, delim))) {
841 strnz__cpy(form->title, token, MAXLEN - 1);
842 }
843 break;
844 default:
845 form_desc_error(form, in_line_num, in_buf, "invalid directive");
846 break;
847 }
848 }
849 fclose(form_desc_fp);
850 if (form->didx < 1 && form->fidx < 1) {
851 ssnprintf(em0, MAXLEN - 1, "%s, line: %d", __FILE__, __LINE__);
852 ssnprintf(em1, MAXLEN - 1, "%s", "Error in description file:");
855 return (1);
856 }
857 return (0);
858}
859/** @brief Read initial data for form fields from a specified input source,
860 such as a file or standard input, and populate the form fields with the
861 data.
862 @ingroup form_engine
863 @param form A pointer to the Form structure containing form data and
864 state.
865 @return 0 on success, or a non-zero value if an error occurs while
866 reading the data or if the specified input source is invalid or empty. */
867int form_read_data(Form *form) {
868 struct stat sb;
869 char in_buf[MAXLEN];
870 char field[MAXLEN];
871 int cmd_key;
872
873 if (!form->f_in_pipe) {
874 if (form->f_in_spec && form->in_spec[0] != '\0') {
875 if ((lstat(form->in_spec, &sb) == -1) || (sb.st_size == 0) ||
876 ((form->in_fp = fopen(form->in_spec, "rb")) == nullptr)) {
878 if (sb.st_size == 0)
879 strnz__cpy(em1, "File is empty", MAXLEN - 1);
880 else
881 strnz__cpy(em1, "File does not exist", MAXLEN - 1);
882 strnz__cpy(em2, "Fields will be blank or zero", MAXLEN - 1);
883 cmd_key = display_error(em0, em1, em2, nullptr);
884 if (cmd_key == KEY_F(9))
885 return (1);
886 }
887 if (form->in_fp == nullptr)
888 return (1);
889 } else
890 return (0);
891 }
892 form->fidx = 0;
893 if (form->in_fp != nullptr) {
894 while ((fgets(in_buf, MAXLEN, form->in_fp)) != nullptr) {
895 if (form->fidx < FIELD_MAXCNT)
896 strnz__cpy(field, in_buf, MAXLEN - 1);
897 form_fmt_field(form, field);
898 form->fidx++;
899 }
900 fclose(form->in_fp);
901 }
902 return (0);
903}
904/** @brief Execute a command specified in the form description file, passing
905 form field values as arguments, and optionally redirecting output to a file.
906 @ingroup form_engine
907 @param form A pointer to the Form structure containing form data and state.
908 @return 0 on success, or a non-zero value if an error occurs while
909 constructing or executing the command. */
910int form_exec_cmd(Form *form) {
911 char earg_str[MAXLEN + 1];
912 int i;
913 strnz__cpy(earg_str, form->receiver_cmd, MAXLEN - 1);
914 for (i = 0; i < form->fcnt; i++) {
915 strnz__cat(earg_str, " ", MAXLEN - 1);
916 strnz__cat(earg_str, form->field[i]->accept_s, MAXLEN - 1);
917 }
918 if (form->f_out_spec && form->f_process) {
919 strnz__cat(earg_str, " >", MAXLEN - 1);
920 strnz__cat(earg_str, form->out_spec, MAXLEN - 1);
921 }
922 shell(earg_str);
923 return 0;
924}
925/** @brief Execute a command specified by the -R option on the form command line
926 @ingroup form_engine
927 @param init A pointer to the Init structure
928 @return 0 on success, or a non-zero value if an error occurs while
929 constructing or executing the command.
930 @details This function constructs a command by taking the receiver_cmd
931 appending field values as arguments, and handling special cases such as
932 multiple command arguments or placeholder substitution. It then executes the
933 command, either displaying the output in a popup view if the command is
934 "view", or executing it directly in a child process for other commands. The
935 function also handles error cases and ensures that resources are properly
936 freed. */
937int form_exec_receiver(Init *init) {
938 int rc = -1;
939 int eargc;
940 char *eargv[MAXARGS];
941 char tmp_str[MAXLEN] = {'\0'};
942 char title[MAXLEN];
943 char sav_arg[MAXLEN];
944 char *out_s;
945 int eargx = 0;
946 int i = 0;
947 pid_t pid = 0;
948 bool f_append_values = false;
949
950 title[0] = '\0';
951 Form *form = init->form;
952 if (form->receiver_cmd[0] == '\0')
953 return -1;
954 // Eliminate leading and trailing quotes
955 if (form->receiver_cmd[0] == '\\' || form->receiver_cmd[0] == '\"') {
956 size_t len = strlen(form->receiver_cmd);
957 if (len > 1 && form->receiver_cmd[len - 1] == '\"') {
958 memmove(form->receiver_cmd, form->receiver_cmd + 1, len - 2);
959 form->receiver_cmd[len - 2] = '\0';
960 }
961 }
962 eargc = str_to_args(eargv, form->receiver_cmd, MAXARGS - 1);
963 tmp_str[0] = '\0';
964 if (form->f_multiple_cmd_args) {
965 // concatenate fields into a single argument
966 for (i = 0; i < form->fcnt; i++) {
967 if (form->field[i]->accept_s[0] && eargc < MAXARGS) {
968 if (tmp_str[0] != '\0')
969 strnz__cat(tmp_str, " ", MAXLEN - 1);
970 strnz__cat(tmp_str, form->field[i]->accept_s, MAXLEN - 1);
971 }
972 }
973 eargv[eargc++] = strdup(tmp_str);
974 } else {
975 f_append_values = false;
976 // find lines with "%%" to determine where to insert field values
977 i = 0;
978 while (i < eargc) {
979 /** This is the line that gets the selected objects */
980 if (strstr(eargv[i], "%%") != nullptr) {
981 tmp_str[0] = '\0';
982 f_append_values = true;
983 strnz__cpy(sav_arg, eargv[i], MAXLEN - 1);
984 eargx = i;
985 break;
986 }
987 i++;
988 }
989 for (i = 0; i < form->fcnt; i++) {
990 // concatenate field values onto tmp_str
991 if (form->field[i]->accept_s[0] && eargc < MAXARGS - 1) {
992 if (f_append_values == true) {
993 if (tmp_str[0] != '\0')
994 strnz__cat(tmp_str, " ", MAXLEN - 1);
995 strnz__cat(tmp_str, form->field[i]->accept_s, MAXLEN - 1);
996 continue;
997 }
998 eargv[eargc++] = strdup(form->field[i]->accept_s);
999 }
1000 }
1001 // replace "%%" with concatenated field values
1002 if (f_append_values == true) {
1003 if (eargv[eargx] != nullptr) {
1004 free(eargv[eargx]);
1005 eargv[eargx] = nullptr;
1006 }
1007 out_s = rep_substring(sav_arg, "%%", tmp_str);
1008 if (out_s == nullptr || out_s[0] == '\0') {
1009 i = 0;
1010 while (i < eargc) {
1011 if (eargv[i] != nullptr)
1012 free(eargv[i]);
1013 i++;
1014 }
1015 Perror("rep_substring() failed in form_exec_objects");
1016 return 1;
1017 }
1018 strnz__cpy(title, out_s, MAXLEN - 1);
1019 eargv[eargx] = strdup(out_s);
1020 if (out_s != nullptr) {
1021 free(out_s);
1022 out_s = nullptr;
1023 }
1024 }
1025 }
1026 if (eargc > 0)
1027 eargv[eargc] = nullptr;
1028 base_name(tmp_str, eargv[0]);
1029 if (tmp_str[0] != '\0' && (strcmp(tmp_str, "view") == 0)) {
1030 /** initialize popup_view arguments and execute popup_view to display
1031 command output within form interface */
1032 init->lines = 60;
1033 init->cols = 80;
1034 init->begy = form->begy + 1;
1035 init->begx = form->begx + 1;
1036 if (title[0] != '\0')
1037 strnz__cpy(init->title, title, MAXLEN - 1);
1038 else
1039 strnz__cpy(init->title, eargv[eargc], MAXLEN - 1);
1040 popup_view(init, eargc, eargv, init->lines, init->cols, init->begy,
1041 init->begx);
1042 i = 0;
1043 while (i < eargc) {
1044 if (eargv[i] != nullptr)
1045 free(eargv[i]);
1046 i++;
1047 }
1048 return 0;
1049 } else {
1050 endwin();
1051 if ((pid = fork()) == -1) {
1052 /** fork failed, free eargv and return error */
1053 i = 0;
1054 while (i < eargc) {
1055 if (eargv[i] != nullptr)
1056 free(eargv[i]);
1057 i++;
1058 }
1059 Perror("fork() failed in form_exec_objects");
1060 return (1);
1061 }
1062 if (pid == 0) {
1063 /** Prevent child process from writing to terminal */
1064 int dev_null = open("/dev/null", O_WRONLY);
1065 if (dev_null == -1) {
1066 Perror("open(/dev/null) failed in init_form child process");
1067 exit(EXIT_FAILURE);
1068 }
1069 dup2(dev_null, STDERR_FILENO);
1070 close(dev_null);
1071 /** Child process to execute command */
1072 execvp(eargv[0], eargv);
1073 /** If execvp returns, it means execution failed, so free eargv
1074 and print error message before exiting */
1075 strnz__cpy(tmp_str, "Can't exec form cmd: ", MAXLEN - 1);
1076 strnz__cat(tmp_str, eargv[0], MAXLEN - 1);
1077 Perror(tmp_str);
1078 exit(EXIT_FAILURE);
1079 }
1080 }
1081 waitpid(pid, nullptr, 0);
1082 reset_prog_mode();
1083 destroy_argv(eargc, eargv);
1085 // werase(stdscr);
1086 // wrefresh(stdscr);
1088 return rc;
1089}
1090/** @brief Write form field values to a specified output destination, such
1091 as a file or standard output, based on the form configuration and user
1092 input.
1093 @ingroup form_engine
1094 @param form A pointer to the Form structure containing form data and
1095 state.
1096 @return 0 on success, or a non-zero value if an error occurs while
1097 writing the data or if the specified output destination is invalid. */
1098int form_write(Form *form) {
1099 int n;
1100 if (form->out_spec[0] == '\0' || strcmp(form->out_spec, "-") == 0 ||
1101 strcmp(form->out_spec, "/dev/stdout") == 0) {
1102 strnz__cpy(form->out_spec, "/dev/stdout", MAXLEN - 1);
1103 close(form->out_fd);
1104 form->out_fd = open(form->out_spec, O_CREAT | O_RDWR | O_TRUNC, 0644);
1105 if (form->out_fd == -1) {
1106 ssnprintf(em0, MAXLEN - 1, "%s, line: %d", __FILE__, __LINE__ - 1);
1107 strnz__cpy(em1, "open ", MAXLEN - 1);
1109 strerror_r(errno, em2, MAXLEN);
1111 return (1);
1112 }
1113 dup2(form->out_fd, STDOUT_FILENO);
1114 form->out_fp = fdopen(STDOUT_FILENO, "w");
1115 form->f_out_spec = true;
1116 form->f_out_pipe = true;
1117 } else {
1118 if ((form->out_fp = fopen(form->out_spec, "w")) == nullptr) {
1119 ssnprintf(em0, MAXLEN - 1, "%s, line: %d", __FILE__, __LINE__ - 1);
1120 strerror_r(errno, em2, MAXLEN);
1122 return (1);
1123 }
1124 }
1125 if (form->out_fp == nullptr) {
1126 ssnprintf(em0, MAXLEN - 1, "%s, line: %d", __FILE__, __LINE__ - 1);
1127 strnz__cpy(em1, "fopen ", MAXLEN - 1);
1129 strerror_r(errno, em2, MAXLEN);
1131 return (1);
1132 }
1133 for (n = 0; n < form->fcnt; n++)
1134 fprintf(form->out_fp, "%s\n", form->field[n]->accept_s);
1135 if (form->out_fp != nullptr)
1136 fclose(form->out_fp);
1137 return (0);
1138}
1139/** @brief Handle errors encountered while parsing the form description
1140 file, providing detailed error messages that include the file name, line
1141 number, and the specific error encountered.
1142 @ingroup form_engine
1143 @param form A pointer to the Form structure containing form data and
1144 state.
1145 @param in_line_num The line number in the description file where the
1146 error occurred.
1147 @param in_buf The content of the line that caused the error, for
1148 context.
1149 @param em A specific error message describing the nature of the error.
1150 @return An integer status code indicating how the user responded to the
1151 error message (e.g., which key they pressed to acknowledge the error). */
1152int form_desc_error(Form *form, int in_line_num, char *in_buf, char *em) {
1153 int cmd_key;
1154 ssnprintf(em0, MAXLEN - 1, "%s: %s", __FILE__, em);
1155 ssnprintf(em1, MAXLEN - 1, "Desc file: %s, line: %d", form->mapp_spec,
1156 in_line_num);
1157 strnz__cpy(em2, in_buf, MAXLEN - 1);
1158 cmd_key = display_error(em0, em1, em2, nullptr);
1159 return cmd_key;
1160}
int form_yx_to_fidx(Form *, int, int)
#define FIELD_MAXLEN
Definition form.h:18
@ FF_INVALID
Definition form.h:68
@ FA_END
Definition form.h:42
@ FA_ACCEPT
Definition form.h:29
@ FA_CALC
Definition form.h:37
@ FA_HELP
Definition form.h:31
@ FA_CANCEL
Definition form.h:33
@ FA_CONTINUE
Definition form.h:27
char ff_tbl[][26]
Definition fields.c:26
#define FIELD_MAXCNT
Definition form.h:19
#define FORM_HELP_FILE
Definition common.h:33
#define P_READ
Definition common.h:50
int popup_view(Init *, int, char **, int, int, int, int)
instantiate a view popup window
Definition popups.c:144
#define P_WRITE
Definition common.h:51
int cp_brackets
Definition dwin.c:190
int cp_nt
Definition dwin.c:183
WINDOW * win_win[MAXWIN]
Definition dwin.c:52
char em1[MAXLEN]
Definition dwin.c:176
#define MAXARGS
Definition cm.h:48
int click_x
Definition dwin.c:81
int cp_nt_hl_rev
Definition dwin.c:186
int wait_timeout
Definition futil.c:152
char stdio_names_str[MAXLEN]
Definition futil.c:134
int win_ptr
Definition dwin.c:164
int click_y
Definition dwin.c:80
char em0[MAXLEN]
Definition dwin.c:175
char * stdio_fdnames(char *, char *)
Definition futil.c:1089
WINDOW * win_box[MAXWIN]
Definition dwin.c:53
int cp_fill_char
Definition dwin.c:189
char em2[MAXLEN]
Definition dwin.c:177
#define BUFSIZ
Definition view.h:31
#define MAXLEN
Definition curskeys.c:15
void mk_filler(char *, int)
#define D_CMD
Definition form_engine.c:26
#define D_FIELD
Definition form_engine.c:27
#define D_CALC
Definition form_engine.c:31
void form_usage()
#define D_TEXT
Definition form_engine.c:28
#define D_HELP
Definition form_engine.c:29
#define D_QUERY
Definition form_engine.c:32
#define D_COMMENT
Definition form_engine.c:25
#define D_HEADER
Definition form_engine.c:30
#define D_GETTER
Definition form_engine.c:33
int xwgetch(WINDOW *, Chyron *, int)
Wrapper for wgetch that handles signals, mouse events, checks for clicks on the chyron line,...
Definition dwin.c:2094
void restore_wins()
Restore all windows after a screen resize.
Definition dwin.c:1225
void win_del()
Delete the current window and its associated box window.
Definition dwin.c:1179
int box_new(int, int, int, int, char *)
Create a new window with optional box and title.
Definition dwin.c:967
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
cchar_t mkcc(int, attr_t, const char *)
Create a cchar_t with the specified color pair index.
Definition dwin.c:748
bool waitpid_with_timeout(pid_t, int)
Wait for a process to finish with a timeout and optional user cancellation.
Definition dwin.c:2033
int Perror(char *)
Display a simple error message window or print to stderr.
Definition dwin.c:1526
void abend(int, char *)
Abnormal program termination.
Definition dwin.c:2018
int display_error(char *, char *, char *, char *)
Display an error message window or print to stderr.
Definition dwin.c:1467
bool is_set_chyron_key(Chyron *, int)
Check if function key label is set.
Definition dwin.c:1743
void set_chyron_key(Chyron *, int, char *, int)
Set chyron key with default color pair (cp_nt_rev).
Definition dwin.c:1783
void display_chyron(WINDOW *, Chyron *, int, int)
Display chyron on window.
Definition dwin.c:1892
Chyron * destroy_chyron(Chyron *chyron)
Destroy Chyron structure.
Definition dwin.c:1722
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
Chyron * new_chyron()
Create and initialize Chyron structure.
Definition dwin.c:1701
int shell(char *)
Execute a shell command.
Definition exec.c:78
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
int form_exec_receiver(Init *)
Execute a command specified by the -R option on the form command line.
int form_desc_error(Form *, int, char *, char *)
Handle errors encountered while parsing the form description file, providing detailed error messages ...
int form_read_data(Form *)
Read initial data for form fields from a specified input source, such as a file or standard input,...
int form_parse_desc(Form *)
Parse the form description file to populate the Form data structure with field definitions,...
int form_write(Form *)
Write form field values to a specified output destination, such as a file or standard output,...
int form_process(Init *)
Handle integration with a getter program which will provide field data.
int form_exec_cmd(Form *)
Execute a command specified in the form description file, passing form field values as arguments,...
int init_form(Init *, int, char **, int, int)
Initialize form data structure and parse description file.
Definition form_engine.c:61
int form_post(Init *)
Handle post-processing after field entry, allowing user to edit data, execute a provider command,...
int form_engine(Init *)
Form main processing loop.
void form_display_fields(Form *)
Display form fields on the screen, populating field values and formatting them according to the form ...
int field_navigator(Form *)
Handle user input for field entry, allowing navigation between fields and looping until an exit actio...
unsigned int display_form(Init *)
Display the form on the screen, including text elements and fields, and set up the form window based ...
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition futil.c:544
int destroy_argv(int argc, char **argv)
Deallocates memory allocated for argument strings in argv.
Definition futil.c:494
size_t trim(char *)
Trims leading and trailing spaces from string s in place.
Definition futil.c:391
bool str_to_lower(char *)
Converts a string to lowercase.
Definition futil.c:508
size_t strnz(char *, size_t)
terminates string at New Line, Carriage Return, or max_len
Definition futil.c:615
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
Definition futil.c:420
size_t strnz__cat(char *, const char *, size_t)
safer alternative to strncat
Definition futil.c:573
char * rep_substring(const char *, const char *, const char *)
Replace all occurrences of "tgt_s" in "org_s" with "rep_s".
Definition futil.c:1440
bool base_name(char *, char *)
Returns the base name of a file specification.
Definition futil.c:1123
int str_to_args(char **, char *, int)
Converts a string into an array of argument strings.
Definition futil.c:440
Form * new_form(Init *, int, char **, int, int)
Create and initialize Form structure.
Definition mem.c:263
Form * destroy_form(Init *init)
Destroy Form structure.
Definition mem.c:286
void sig_prog_mode()
Set up signal handlers for interrupt signals.
Definition sig.c:62
char title[MAXLEN]
Definition common.h:129
char mapp_help[MAXLEN]
Definition common.h:148
int begx
Definition common.h:118
Form * form
Definition common.h:184
int cols
Definition common.h:116
int begy
Definition common.h:117
int lines
Definition common.h:115
bool active
Definition cm.h:336
int l
Definition cm.h:348
ChyronKey * key[CHYRON_KEYS]
Definition cm.h:345
int len
Definition form.h:106
int col
Definition form.h:102
char str[SCR_COLS]
Definition form.h:104
int line
Definition form.h:100
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
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
cchar_t brktr
Definition form.h:294
FILE * out_fp
Definition form.h:161
Text * text[FIELD_MAXCNT]
Definition form.h:338
bool f_in_pipe
Definition form.h:221
bool f_mapp_spec
Definition form.h:192
WINDOW * box
Definition form.h:156
Field * field[FIELD_MAXCNT]
Definition form.h:351
char receiver_cmd[MAXLEN]
Definition form.h:178
bool f_process
Definition form.h:246
int didx
Definition form.h:323
int begy
Definition form.h:151
char provider_cmd[MAXLEN]
Definition form.h:170
bool f_query
Definition form.h:248
int out_fd
Definition form.h:165
int cols
Definition form.h:150
int lines
Definition form.h:149
int fcnt
Definition form.h:316
int begx
Definition form.h:153
bool f_out_pipe
Definition form.h:226
int fidx
Definition form.h:308
bool f_provider_cmd
Definition form.h:256
bool f_calculate
Definition form.h:244
char fill_char[4]
Definition form.h:297
cchar_t brktl
Definition form.h:291
bool f_help_spec
Definition form.h:231
FILE * in_fp
Definition form.h:159
char out_spec[MAXLEN]
Definition form.h:208
Chyron * chyron
Definition form.h:363
bool f_receiver_cmd
Definition form.h:263
bool f_multiple_cmd_args
Definition form.h:243
char in_spec[MAXLEN]
Definition form.h:201
char mapp_spec[FIELD_MAXLEN]
Definition form.h:167
char title[MAXLEN]
Definition form.h:157
char brackets[3]
Definition form.h:279
int dcnt
Definition form.h:330
bool f_out_spec
Definition form.h:218
WINDOW * win
Definition form.h:155
bool f_in_spec
Definition form.h:215
char help_spec[MAXLEN]
Definition form.h:194