C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
pick_engine.c
Go to the documentation of this file.
1/** @file pick_engine.c
2 @brief pick from a list of choices
3 @author Bill Waller
4 Copyright (c) 2025
5 MIT License
6 billxwaller@gmail.com
7 @date 2026-02-09
8 */
9
10/** @defgroup pick_engine Object Selection
11 @brief Navigate, Select, and Perform Action on Objects
12 */
13
14#include <common.h>
15#include <fcntl.h>
16#include <stdbool.h>
17#include <stdlib.h>
18#include <string.h>
19#include <sys/stat.h>
20#include <sys/wait.h>
21#include <termios.h>
22#include <unistd.h>
23
26int pick_engine(Init *);
27void save_object(Pick *, char *);
28int picker(Init *, char *field);
29void display_page(Pick *);
30void reverse_object(Pick *);
31void unreverse_object(Pick *);
32void toggle_object(Pick *);
33int output_objects(Pick *);
34int exec_objects(Init *);
35int open_pick_win(Init *);
36void display_pick_help(Init *);
37int read_pick_input(Init *);
38void deselect_object(Pick *);
39
40int pipe_fd[2];
41
42char const pagers_editors[12][10] = {"view", "view", "less", "more",
43 "vi", "vim", "nano", "nvim",
44 "pico", "emacs", "edit", ""};
45
46/** @brief Initializes pick structure and opens pick input file or pipe
47 * @ingroup pick_engine
48 @param init Pointer to Init structure
49 @param argc Argument count
50 @param argv Argument vector
51 @param begy Beginning y coordinate for pick window
52 @param begx Beginning x coordinate for pick window
53 @details If provider_cmd is specified, it takes precedence over in_spec and
54 input file arguments.
55 provider_cmd is executed and its output is read as pick input
56 If provider_cmd is not specified, in_spec is used to read pick
57 input from a file or stdin
58 If provider_cmd is specified, it is executed and its output is
59 read as pick input */
60int init_pick(Init *init, int argc, char **argv, int begy, int begx) {
61 struct stat sb;
62 char *s_argv[MAXARGS];
63 int s_argc;
64 char tmp_str[MAXLEN];
65 pid_t pid = 0;
66
67 Pick *pick = new_pick(init, argc, argv, begy, begx);
68 if (init->pick != pick)
69 abend(-1, "init->pick != pick\n");
70 SIO *sio = init->sio;
71 if (pick->provider_cmd[0] != '\0') {
72 s_argc = str_to_args(s_argv, pick->provider_cmd, MAXARGS - 1);
73 if (pipe(pipe_fd) == -1) {
74 Perror("pipe(pipe_fd) failed in init_pick");
75 return (1);
76 }
77 if ((pid = fork()) == -1) {
78 Perror("fork() failed in init_pick");
79 return (1);
80 }
81 if (pid == 0) {
82 /** Prevent child process from writing to terminal */
83 int dev_null = open("/dev/null", O_WRONLY);
84 if (dev_null == -1) {
85 Perror("open(/dev/null) failed in init_pick child process");
86 exit(EXIT_FAILURE);
87 }
88 dup2(dev_null, STDERR_FILENO);
89 close(dev_null);
90 /** Close read end of pipe as Child only needs to write to pipe */
91 close(pipe_fd[P_READ]);
92 /** Connect CHILD STDOUT to write end of pipe */
93 dup2(pipe_fd[P_WRITE], STDOUT_FILENO);
94 /** STDOUT attached to write end of pipe, so close pipe fd */
95 close(pipe_fd[P_WRITE]);
96 /** Spawn Child to execute provider_cmd */
97 execvp(s_argv[0], s_argv);
98 strnz__cpy(tmp_str, "Can't exec pick start cmd: ", MAXLEN - 1);
99 strnz__cat(tmp_str, s_argv[0], MAXLEN - 1);
100 Perror(tmp_str);
101 exit(EXIT_FAILURE);
102 }
103 /** Return to Parent
104 Close write end of pipe as Parent only needs to read from pipe */
105 close(pipe_fd[P_WRITE]);
106 /** Open a file pointer on read end of pipe */
107 pick->in_fp = fdopen(pipe_fd[P_READ], "rb");
108 pick->f_in_pipe = true;
109 destroy_argv(s_argc, s_argv);
110 } else {
111 if ((pick->in_spec[0] == '\0') || strcmp(pick->in_spec, "-") == 0 ||
112 strcmp(pick->in_spec, "/dev/stdin") == 0) {
113 strnz__cpy(pick->in_spec, "/dev/stdin", MAXLEN - 1);
114 pick->in_fp = fdopen(STDIN_FILENO, "rb");
115 pick->f_in_pipe = true;
116 }
117 }
118 if (!pick->f_in_pipe) {
119 /** No provider_cmd specified, so read pick input from file or stdin */
120 if (lstat(pick->in_spec, &sb) == -1) {
121 strnz__cpy(tmp_str, "Can\'t stat pick input file: ", MAXLEN - 1);
122 strnz__cat(tmp_str, pick->in_spec, MAXLEN - 1);
123 Perror(tmp_str);
124 return (1);
125 }
126 if (sb.st_size == 0) {
127 strnz__cpy(tmp_str, "Pick input file empty: ", MAXLEN - 1);
128 strnz__cat(tmp_str, pick->in_spec, MAXLEN - 1);
129 Perror(tmp_str);
130 return (1);
131 }
132 if ((pick->in_fp = fopen(pick->in_spec, "rb")) == nullptr) {
133 strnz__cpy(tmp_str, "Can't open pick input file: ", MAXLEN - 1);
134 strnz__cat(tmp_str, pick->in_spec, MAXLEN - 1);
135 Perror(tmp_str);
136 return (1);
137 }
138 }
139 /*------------------------------------------------------------*/
140 bool f_wait = false;
141 int ready;
142 fd_set read_fds;
143 struct timeval timeout;
144 Chyron *wait_chyron;
145 WINDOW *wait_win;
146 int remaining = 0;
147 if (pick->in_fp == nullptr) {
148 Perror("No pick input available");
149 return (1);
150 }
151 int in_fd = fileno(pick->in_fp);
152 FD_ZERO(&read_fds);
153 FD_SET(in_fd, &read_fds);
154 timeout.tv_sec = 0;
155 timeout.tv_usec =
156 200000; /**< Initial timeout of 200ms to check for pick input */
157 ready = select(in_fd + 1, &read_fds, nullptr, nullptr, &timeout);
158 if (ready == 0) {
159 f_wait = true;
160 remaining = wait_timeout;
161 wait_chyron = wait_mk_chyron();
162 wait_win = wait_mk_win(wait_chyron, "WAITING for PICK INPUT");
163 int in_key = 0;
164 while (ready == 0 && remaining > 0 && in_key != KEY_F(9)) {
165 in_key = wait_continue(wait_win, wait_chyron, remaining);
166 if (in_key == KEY_F(9))
167 break;
168 FD_ZERO(&read_fds);
169 FD_SET(in_fd, &read_fds);
170 timeout.tv_sec = 0;
171 timeout.tv_usec = 0;
172 ready = select(in_fd + 1, &read_fds, nullptr, nullptr, &timeout);
173 remaining--;
174 }
175 if (f_wait) {
176 if (wait_chyron != nullptr)
177 wait_destroy(wait_chyron);
178 }
179 if (in_key == KEY_F(9)) {
180 if (pick->f_in_pipe && pid > 0) {
181 /** If user cancels while waiting for pick input, kill
182 * provider_cmd child process and close pipe */
183 kill(pid, SIGKILL);
184 waitpid(pid, nullptr, 0);
185 close(pipe_fd[P_READ]);
186 }
187 Perror("No pick input available");
188 return (1);
189 }
190 }
191 if (ready == -1) {
192 Perror("Error waiting for pick input");
193 if (pick->f_in_pipe && pid > 0) {
194 /** If error occurs while waiting for pick input, kill provider_cmd
195 * child process and close pipe */
196 kill(pid, SIGKILL);
197 waitpid(pid, nullptr, 0);
198 close(pipe_fd[P_READ]);
199 }
200 return (1);
201 }
202 if (ready == 0) {
203 Perror("Timeout waiting for pick input");
204 if (pick->f_in_pipe && pid > 0) {
205 /** If timeout occurs while waiting for pick input, kill
206 * provider_cmd child process and close pipe */
207 kill(pid, SIGKILL);
208 waitpid(pid, nullptr, 0);
209 close(pipe_fd[P_READ]);
210 }
211 return (1);
212 }
213 if (ready == 1 && !FD_ISSET(in_fd, &read_fds)) {
214 Perror("Unexpected error waiting for pick input");
215 if (pick->f_in_pipe && pid > 0) {
216 /** If unexpected error occurs while waiting for pick input, kill
217 * provider_cmd child process and close pipe */
218 kill(pid, SIGKILL);
219 waitpid(pid, nullptr, 0);
220 close(pipe_fd[P_READ]);
221 }
222 return (1);
223 }
224 /*------------------------------------------------------------*/
226 if (pick->f_in_pipe && pid > 0) {
227 /** Wait for provider_cmd child process to finish before proceeding */
229 close(pipe_fd[P_READ]);
230 dup2(sio->stdin_fd, STDIN_FILENO);
231 dup2(sio->stdout_fd, STDOUT_FILENO);
234 keypad(pick->win, true);
235 }
236 if (pick->m_cnt == 0) {
237 Perror("No pick objects available");
238 return (1);
239 }
240 /** Enter pick_engine */
241 pick->m_idx = 0;
242 pick->d_idx = 0;
243 while (pick->m_idx < pick->m_cnt)
244 pick->d_object[pick->d_idx++] = pick->m_object[pick->m_idx++];
245 pick->d_cnt = pick->d_idx;
246 pick_engine(init);
247 win_del();
248 return 0;
249}
250/** @brief Reads pick input from file pointer and saves objects into pick
251 structure
252 * @ingroup pick_engine
253 @param init Pointer to Init structure containing pick information
254 @return 0 on success, -1 if no objects were read
255 @details Reads lines from pick->in_fp and saves them as objects in the pick
256 structure using save_object function. If no objects are read, returns -1.
257 Otherwise, sets obj_cnt to the number of objects read and resets obj_idx to 0
258 before returning 0. */
259int read_pick_input(Init *init) {
260 int i;
261
262 Pick *pick = init->pick;
263 pick->select_cnt = 0;
264 pick->tbl_pages = 1;
265
266 if (pick->in_fp) {
267 while (fgets(pick->in_buf, sizeof(pick->in_buf), pick->in_fp) !=
268 nullptr)
269 save_object(pick, pick->in_buf);
270 } else
271 for (i = 1; i < pick->argc; i++)
272 save_object(pick, pick->argv[i]);
273 if (pick->in_fp != nullptr)
274 fclose(pick->in_fp);
275 if (!pick->m_idx)
276 return (-1);
277 pick->m_cnt = pick->m_idx;
278 return 0;
279}
280/** @brief Initializes pick interface, calculates window size and position, and
281 enters picker loop
282 * @ingroup pick_engine
283 @param init Pointer to Init structure containing pick information
284 @return Count of selected objects on success, -1 if user cancels
285 @details Initializes key command strings for chyron display and calculates
286 pick window size and position based on terminal size and pick parameters. Opens
287 pick window and displays first page of objects. Enters picker loop to handle
288 user input and interactions. If user cancels selection, returns -1. If user
289 accepts selection, returns count of selected objects. */
290int pick_engine(Init *init) {
291 int rc;
292 int maxy, maxx, win_maxy, win_maxx;
293 int tbl_max_cols, pg_max_objs;
294
295 getmaxyx(stdscr, maxy, maxx);
296 /** Calculate pick window size and position based on terminal size and pick
297 parameters */
298 win_maxy = min(((maxy * 8) / 10), (maxy - pick->begy - 1));
299 win_maxx = min(((maxx * 9) / 10), (maxx - pick->begx - 1));
302 if (pick->d_cnt <= win_maxy) {
304 pick->tbl_cols = 1;
305 } else {
306 tbl_max_cols = (win_maxx / (pick->tbl_col_width + 1));
307 pg_max_objs = win_maxy * tbl_max_cols;
308 if (pick->d_cnt > pg_max_objs)
309 pick->tbl_cols = tbl_max_cols;
310 else
311 pick->tbl_cols = pick->d_cnt / win_maxy;
312 pick->tbl_lines = pick->d_cnt / tbl_max_cols;
313 }
314 pick->tbl_pages = (pick->tbl_lines / (win_maxy - 1)) + 1;
317 pick->tbl_page = 0;
318 if (pick->begy == 0)
319 pick->begy = (LINES - pick->win_lines) / 5;
320 else if (pick->begy + pick->win_lines > LINES - 4)
321 pick->begy = LINES - pick->win_lines - 2;
323
325 set_chyron_key(pick->chyron, 1, "F1 Help", KEY_F(1));
326 set_chyron_key(pick->chyron, 2, "F9 Cancel", KEY_F(9));
327 set_chyron_key(pick->chyron, 3, "F10 Accept", KEY_F(10));
328 set_chyron_key(pick->chyron, 4, "Sp Toggle", KEY_F(13));
329 set_chyron_key(pick->chyron, 5, "Tab Edit", '\t');
330 if (pick->tbl_pages > 1) {
331 set_chyron_key(pick->chyron, 11, "PgUp", KEY_PPAGE);
332 set_chyron_key(pick->chyron, 12, "PgDn", KEY_NPAGE);
333 }
335 if (pick->chyron->l > win_maxx)
340 if (pick->begx + pick->win_width > COLS - 2)
341 pick->begx = COLS - pick->win_width - 2;
342 else if (pick->begx == 0)
343 pick->begx = (COLS - pick->win_width) / 2;
344
345 rc = open_pick_win(init);
346 if (rc)
347 return (rc);
348
349 /** Enter picker loop to handle user input and interactions */
350 pick->d_idx = 0;
351 pick->x = 1;
352 char field[MAXLEN]; /**< Buffer for user input in the field */
353 field[0] = '\0';
354 do {
355 rc = picker(init, field);
356 if (rc == KEY_F(9))
357 break;
358 if (rc == -1)
359 break;
360 else {
361 if (pick->select_cnt > 0) {
364 if (pick->f_cmd && pick->cmd[0])
365 exec_objects(init);
366 }
367 }
369 } while (1);
371 return (rc);
372}
373/** @brief Saves a string as an object in the pick structure
374 * @ingroup pick_engine
375 @param pick Pointer to Pick structure
376 @param s String to save as an object
377 @details If the current object index is less than the maximum allowed, saves
378 the string as an object in the pick structure. Updates the column width if
379 necessary and marks the object as not selected. Increments the object index
380 for the next object to be saved. */
381void save_object(Pick *pick, char *s) {
382 int l;
383
384 if (pick->m_idx < OBJ_MAXCNT - 1) {
385 l = strlen(s);
386 if (l > OBJ_MAXLEN - 1)
387 s[OBJ_MAXLEN - 1] = '\0';
388 pick->tbl_col_width = max(pick->tbl_col_width, l);
389 l = max(l, 1);
390 pick->m_object[pick->m_idx] = (char *)calloc(l + 1, sizeof(char));
392 pick->f_selected[pick->m_idx] = false;
393 pick->m_idx++;
394 }
395}
396
397/** @brief Displays current page of objects in pick window
398 * @ingroup pick_engine
399 @param pick Pointer to Pick structure containing objects and display
400 information
401 @details Clears the pick window and displays the current page of objects
402 based on the current table page, line, and column. Marks selected objects with
403 an asterisk. Updates the chyron with page information at the bottom of the pick
404 window. */
405void display_page(Pick *pick) {
406 int col;
407 for (pick->y = 0; pick->y < pick->pg_lines; pick->y++) {
408 wmove(pick->win, pick->y, 0);
409 wclrtoeol(pick->win);
410 }
411 pick->d_idx = pick->tbl_page * pick->pg_lines * pick->tbl_cols;
412 for (col = 0; col < pick->tbl_cols; col++) {
413 pick->x = col * (pick->tbl_col_width + 1) + 1;
414 pick->y = 0;
415 while (pick->d_idx < pick->d_cnt && pick->y < pick->pg_lines) {
416 if (pick->f_selected[pick->d_idx])
417 mvwaddstr(pick->win, pick->y, pick->x - 1, "*");
418 mvwaddstr_fill(pick->win, pick->y++, pick->x,
419 pick->d_object[pick->d_idx++], pick->tbl_col_width);
420 }
421 }
422 pick->d_idx -= 1;
423 pick->tbl_lines = pick->d_cnt;
424 pick->tbl_pages = ((pick->tbl_lines + pick->pg_lines - 1) / pick->pg_lines);
425 if (pick->y < pick->pg_lines) {
426 pick->y_offset = pick->pg_lines - pick->y;
427 wscrl(pick->win, -pick->y_offset);
428 } else
429 pick->y_offset = 0;
430 wrefresh(pick->win);
431}
432/** @brief Displays current page of objects in pick window
433 @ingroup pick_engine
434 @param pick Pointer to Pick structure containing objects and display
435 information
436 @param s String to filter objects by
437 @details Clears the pick window and displays the current page of objects
438 based on the current table page, line, and column. Marks selected objects
439 with an asterisk. Updates the chyron with page information at the bottom of
440 the pick window. */
441int match_objects(Pick *pick, char *s) {
442 /** pick->m_idx Master (as read from input) */
443 /** pick->d_idx Display (to display) */
444 pick->m_idx = 0;
445 pick->d_idx = 0;
446 while (pick->m_idx < pick->m_cnt) {
447 if (s == nullptr || s[0] == '\0' ||
448 strstr(pick->m_object[pick->m_idx], s) != nullptr) {
449 pick->d_object[pick->d_idx++] = pick->m_object[pick->m_idx];
450 }
451 pick->m_idx++;
452 }
453 pick->d_cnt = pick->d_idx;
454 return pick->d_cnt;
455}
456/** @brief Reverses the display of the currently selected object in pick window
457 * @ingroup pick_engine
458 @param pick Pointer to Pick structure containing object and display
459 information
460 @details Calculates the x coordinate for the currently selected object based
461 on the current table column and column width. Moves the cursor to the object's
462 position in the pick window, turns on reverse video attribute, and displays
463 the object's text. Turns off reverse video attribute and refreshes the pick
464 window to show the updated display. Moves the cursor back to the position
465 before the object text for potential further interactions. */
466void reverse_object(Pick *pick) {
467 if (pick->d_idx >= pick->d_cnt)
468 pick->d_idx = pick->d_cnt - 1;
469 pick->x = pick->tbl_col * (pick->tbl_col_width + 1) + 1;
470 pick->tbl_line = (pick->d_idx / pick->tbl_cols) % pick->pg_lines;
471 pick->y = pick->tbl_line + pick->y_offset;
472 pick->d_idx = pick->tbl_page * pick->pg_lines * pick->tbl_cols +
473 pick->tbl_col * pick->pg_lines + pick->tbl_line;
474 wmove(pick->win, pick->y, pick->x);
475 wattron(pick->win, WA_REVERSE);
478 wattroff(pick->win, WA_REVERSE);
479 wmove(pick->win, pick->y, pick->x - 1);
480}
481/** @brief Unreverses the display of the currently selected object in pick
482 window
483 @ingroup pick_engine
484 @param pick Pointer to Pick structure containing object and display
485 information
486 @details Calculates the x coordinate for the currently selected object based
487 on the current table column and column width. Moves the cursor to the
488 object's position in the pick window and displays the object's text without
489 reverse video attribute. Refreshes the pick window to show the updated
490 display. Moves the cursor back to the position before the object text for
491 potential further interactions. */
492void unreverse_object(Pick *pick) {
493 if (pick->d_idx >= pick->d_cnt)
494 pick->d_idx = pick->d_cnt - 1;
495 pick->x = pick->tbl_col * (pick->tbl_col_width + 1) + 1;
496 pick->tbl_line = (pick->d_idx / pick->tbl_cols) % pick->pg_lines;
497 pick->y = pick->tbl_line + pick->y_offset;
498 pick->d_idx = pick->tbl_page * pick->pg_lines * pick->tbl_cols +
499 pick->tbl_col * pick->pg_lines + pick->tbl_line;
500 wmove(pick->win, pick->y, pick->x);
503 wmove(pick->win, pick->y, pick->x - 1);
504}
505/** @brief Toggles the selection state of the currently selected object in pick
506 window
507 @ingroup pick_engine
508 @param pick Pointer to Pick structure containing object and selection
509 information
510 @details Calculates the x coordinate for the currently selected object based
511 on the current table column and column width. If the object is currently
512 selected, it is deselected by updating the selection count, marking it as not
513 selected, and displaying a space before the object text. If the object is not
514 currently selected, it is selected by updating the selection count, marking
515 it as selected, and displaying an asterisk before the object text. Refreshes
516 the pick window to show the updated display. Moves the cursor back to the
517 position before the object text for potential further interactions. */
518void toggle_object(Pick *pick) {
519 pick->x = pick->tbl_col * (pick->tbl_col_width + 1) + 1;
520 if (pick->f_selected[pick->d_idx]) {
521 pick->select_cnt--;
522 pick->f_selected[pick->d_idx] = false;
523 mvwaddstr(pick->win, pick->y, pick->x - 1, " ");
524 } else {
525 pick->select_cnt++;
526 pick->f_selected[pick->d_idx] = true;
527 mvwaddstr(pick->win, pick->y, pick->x - 1, "*");
528 }
529}
530/** @brief Deselects the currently selected object in pick window
531 @ingroup pick_engine
532 @details like toggle, but only deselects object */
533void deselect_object(Pick *pick) {
534 pick->x = pick->tbl_col * (pick->tbl_col_width + 1) + 1;
535 if (pick->f_selected[pick->d_idx]) {
536 pick->select_cnt--;
537 pick->f_selected[pick->d_idx] = false;
538 mvwaddstr(pick->win, pick->y, pick->x - 1, " ");
539 }
540}
541/** @brief Outputs selected objects to specified output file
542 @ingroup pick_engine
543 @param pick Pointer to Pick structure containing selected objects and
544 output file information
545 @return 0 on success, 1 on failure
546 @details If output file cannot be opened, an error message is printed and
547 the function returns 1. Otherwise, selected objects are written to the
548 output file, one per line, and the file is closed before returning 0.
549*/
550int output_objects(Pick *pick) {
551 char tmp_str[MAXLEN];
552 int m;
553 if ((pick->out_fp = fopen(pick->out_spec, "w")) == nullptr) {
554 m = MAXLEN - 30;
555 strnz__cpy(tmp_str, "Can't open pick output file: ", m);
556 m -= strlen(pick->in_spec);
557 strnz__cat(tmp_str, pick->out_spec, m);
558 }
559 for (pick->d_idx = 0; pick->d_idx < pick->d_cnt; pick->d_idx++) {
560 if (pick->f_selected[pick->d_idx])
561 fprintf(stdout, "%s\n", pick->d_object[pick->d_idx]);
562 }
563 fflush(stdout);
564 if (pick->out_fp != nullptr)
565 fclose(pick->out_fp);
566 return (0);
567}
568/** @brief Executes specified command with selected objects as arguments
569 @ingroup pick_engine
570 @param init Pointer to Init structure
571 @return 0 on success, 1 on failure
572 @details Parses command string and appends selected objects as arguments to
573 the command. If command contains "%%", it is replaced with a space- separated
574 list of selected objects. Executes the command using execvp in a child
575 process and waits for it to finish. If the command is a pager or editor, it
576 is executed within the pick interface using popup_view instead of execvp.
577 If f_append_objects is true, the argument containing %% is replaced with
578 the concatenated selected objects. If f_append_objects is false, selected
579 objects are added as separate arguments and the original command arguments
580 remain unchanged.
581 eargv should be null-terminated to indicate the end of arguments for
582 execvp
583 Memory allocated for arguments is freed after execution to prevent
584 memory leaks.
585 If execvp fails, an error message is printed and the child process
586 exits with failure status
587 The parent process waits for the child process to finish before
588 proceeding and restores terminal settings
589 If the command is a pager or editor, it is executed within the pick
590 interface using popup_view instead of execvp
591 The base name of the command is extracted to check if it is a pager or
592 editor
593 If the command is a pager or editor, the pick interface is used to
594 display the command output instead of executing it in a separate terminal
595 This allows the user to view the command output without leaving the pick
596 interface and provides a more seamless user experience.
597 If the command is not a pager or editor, it is executed in a separate
598 terminal and the pick interface is restored after execution
599 If the command to be executed is view, an external command is not
600 needed, instead the popup_view function can be used to display the output
601 within the pick interface */
602int exec_objects(Init *init) {
603 int rc = -1;
604 int eargc;
605 char *eargv[MAXARGS];
606 char tmp_str[MAXLEN] = {'\0'};
607 char title[MAXLEN];
608 char sav_arg[MAXLEN];
609 char *out_s;
610 int eargx = 0;
611 int i = 0;
612 pid_t pid = 0;
613 bool f_append_objects = false;
614
615 title[0] = '\0';
616 if (pick->cmd[0] == '\0')
617 return -1;
618 if (pick->cmd[0] == '\\' || pick->cmd[0] == '\"') {
619 size_t len = strlen(pick->cmd);
620 if (len > 1 && pick->cmd[len - 1] == '\"') {
621 memmove(pick->cmd, pick->cmd + 1, len - 2);
622 pick->cmd[len - 2] = '\0';
623 }
624 }
625 eargc = str_to_args(eargv, pick->cmd, MAXARGS - 1);
626 tmp_str[0] = '\0';
628 for (i = 0; i < pick->d_cnt; i++) {
629 if (pick->f_selected[i] && eargc < MAXARGS) {
630 if (tmp_str[0] != '\0')
631 strnz__cat(tmp_str, " ", MAXLEN - 1);
633 }
634 }
635 eargv[eargc++] = strdup(tmp_str);
636 } else {
637 f_append_objects = false;
638 i = 0;
639 while (i < eargc) {
640 /** This is the line that gets the selected objects */
641 if (strstr(eargv[i], "%%") != nullptr) {
642 tmp_str[0] = '\0';
643 f_append_objects = true;
644 strnz__cpy(sav_arg, eargv[i], MAXLEN - 1);
645 eargx = i;
646 break;
647 }
648 i++;
649 }
650 for (i = 0; i < pick->d_cnt; i++) {
651 /** append arguments onto tmp_str */
652 if (pick->f_selected[i] && eargc < MAXARGS - 1) {
653 if (f_append_objects == true) {
654 if (tmp_str[0] != '\0')
655 strnz__cat(tmp_str, " ", MAXLEN - 1);
657 continue;
658 }
659 eargv[eargc++] = strdup(pick->d_object[i]);
660 }
661 }
662 if (f_append_objects == true) {
663 if (eargv[eargx] != nullptr) {
664 free(eargv[eargx]);
665 eargv[eargx] = nullptr;
666 }
667 out_s = rep_substring(sav_arg, "%%", tmp_str);
668 if (out_s == nullptr || out_s[0] == '\0') {
669 i = 0;
670 while (i < eargc) {
671 if (eargv[i] != nullptr)
672 free(eargv[i]);
673 i++;
674 }
675 Perror("rep_substring() failed in exec_objects");
676 return 1;
677 }
678 strnz__cpy(title, out_s, MAXLEN - 1);
679 eargv[eargx] = strdup(out_s);
680 if (out_s != nullptr) {
681 free(out_s);
682 out_s = nullptr;
683 }
684 }
685 }
686 strnz__cpy(tmp_str, eargv[0], MAXLEN - 1);
687 eargv[eargc] = nullptr;
688 char *sp;
689 char *tok;
690 tok = strtok_r(tmp_str, " ", &sp);
691 strnz__cpy(sav_arg, tok, MAXLEN - 1);
692 base_name(tmp_str, sav_arg);
693 if (tmp_str[0] != '\0' &&
694 (strcmp(tmp_str, "view") == 0 || strcmp(tmp_str, "view") == 0)) {
695 /** initialize popup_view arguments and execute popup_view to display
696 command output within pick interface */
697 init->lines = 60;
698 init->cols = 80;
699 init->begy = pick->begy + 1;
700 init->begx = pick->begx + 1;
701 if (title[0] != '\0')
702 strnz__cpy(init->title, title, MAXLEN - 1);
703 else
704 strnz__cpy(init->title, eargv[eargc], MAXLEN - 1);
705 popup_view(init, eargc, eargv, init->lines, init->cols, init->begy,
706 init->begx);
707 i = 0;
708 while (i < eargc) {
709 if (eargv[i] != nullptr)
710 free(eargv[i]);
711 i++;
712 }
713 return 0;
714 } else {
715 if ((pid = fork()) == -1) {
716 /** fork failed, free eargv and return error */
717 i = 0;
718 while (i < eargc) {
719 if (eargv[i] != nullptr)
720 free(eargv[i]);
721 i++;
722 }
723 Perror("fork() failed in exec_objects");
724 return (1);
725 }
726 if (pid == 0) {
727 /** Prevent child process from writing to terminal */
728 int dev_null = open("/dev/null", O_WRONLY);
729 if (dev_null == -1) {
730 Perror("open(/dev/null) failed in init_pick child process");
731 exit(EXIT_FAILURE);
732 }
733 dup2(dev_null, STDERR_FILENO);
734 close(dev_null);
735 /** Child process to execute command */
736 execvp(eargv[0], eargv);
737 /** If execvp returns, it means execution failed, so free eargv
738 and print error message before exiting */
739 strnz__cpy(tmp_str, "Can't exec pick cmd: ", MAXLEN - 1);
740 strnz__cat(tmp_str, eargv[0], MAXLEN - 1);
741 Perror(tmp_str);
742 exit(EXIT_FAILURE);
743 }
744 }
745 waitpid(pid, nullptr, 0);
746 destroy_argv(eargc, eargv);
749 werase(stdscr);
750 wrefresh(stdscr);
752 return rc;
753}
754/** @brief Initializes the pick window based on the parameters specified in the
755Pick structure
756 @ingroup pick_engine
757 @param init Pointer to Init structure containing pick information
758 @return 0 on success, 1 on failure
759 @details Creates a new window for the pick interface using win_new function
760with the specified parameters from the Pick structure. If window creation fails,
761an error message is printed and the function returns 1. Otherwise, initializes
762the window and box pointers in the Pick structure, sets scrollok and keypad
763options for the window, and returns 0 on success. */
764int open_pick_win(Init *init) {
765 char tmp_str[MAXLEN];
766 pick = init->pick;
768 pick->title, true)) {
769 ssnprintf(tmp_str, MAXLEN - 1, "box2_new(%d, %d, %d, %d, %s) failed",
772 Perror(tmp_str);
773 return (1);
774 }
779 keypad(pick->win, true);
780 return 0;
781}
782/** @brief Displays the help screen for the pick interface using view
783 @ingroup pick_engine
784 @param init Pointer to Init structure containing pick information
785 @details Initializes the help_spec field in the Pick structure with the
786 path to the pick help file. Then, constructs the argument list for
787 executing popup_view with the help file as an argument. Finally, calls
788 popup_view function to display the help screen within the pick interface. */
789void display_pick_help(Init *init) {
790 int eargc;
791 char *eargv[MAXARGS];
792 char tmp_str[MAXLEN];
793 if (pick->f_help_spec && pick->help_spec[0] != '\0')
795 else {
796 strnz__cpy(tmp_str, init->mapp_help, MAXLEN - 1);
797 strnz__cat(tmp_str, "/", MAXLEN - 1);
799 }
800 eargc = 0;
801 eargv[eargc++] = strdup("view");
802 eargv[eargc++] = strdup("-Nf");
803 eargv[eargc++] = strdup(tmp_str);
804 eargv[eargc] = nullptr;
805 init->lines = 30;
806 init->cols = 76;
807 init->begy = pick->begy + 1;
808 init->begx = pick->begx + 1;
809 strnz__cpy(init->title, "Pick Help", MAXLEN - 1);
810 popup_view(init, eargc, eargv, init->lines, init->cols, init->begy,
811 init->begx);
812 destroy_argv(eargc, eargv);
813 return;
814}
815/** @brief Main loop for handling user input and interactions in the pick
816 interface
817 @ingroup pick_engine
818 @param init Pointer to Init structure containing pick information
819 @param field Buffer for user input in the field
820 @return Count of selected objects on success, -1 if user cancels
821 @details The first loop handles navigation through the pick table.
822 The second loop handles user input for selecting/deselecting objects,
823 accepting the selection, or canceling the selection. Depending on the key
824 pressed, the appropriate action is taken, such as toggling selection, moving
825 to the next/previous object, or displaying the help screen. If the user
826 accepts the selection, the count of selected objects is returned. If the user
827 cancels the selection, -1 is returned.
828 */
829int picker(Init *init, char *field) {
830 bool f_insert = false; /* Flag to indicate if insert mode is active */
831 char filler_s[MAXLEN]; /* buffer for filling the field with spaces */
832 int line = 0; /* Starting line for field input */
833 int col = 1; /* Starting column for field input leaving space for > */
834 char *s; /* source pointer for editing operations */
835 char *d; /* destination pointer for editing operations */
836 char *e; /* end pointer for editing operations */
837 char *accept_s; /* pointer to field buffer */
838 char *fstart; /* start of field buffer */
839 char *fend; /* end of field buffer */
840 char *str_end; /* end of content string */
841 accept_s = field;
842 fstart = accept_s;
843 int flen = pick->win_width - 4;
844 char *ptr; /* pointer to current cursor position within field buffer */
845 int pos;
846 char prev_field[MAXLEN];
847 int prev_pos;
848 char *prev_ptr;
849
850 pick = init->pick;
851 win = pick->win;
852 WINDOW *win2 = pick->win2;
853 fend = fstart + flen;
854 str_end = fstart + strlen(fstart); /* End of field content */
855
856 ptr = str_end;
857 click_x = -1;
858 click_y = click_x = -1;
859 char tmp_str[MAXLEN];
860
861 mousemask(BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED, nullptr);
863 f_insert = false;
867
868 cchar_t cc = {0};
869 wchar_t wstr[2] = {BW_RAN, L'\0'};
870 setcchar(&cc, wstr, WA_NORMAL, cp_box, nullptr);
871 mvwadd_wch(pick->box, pick->separator_line + 1, 1, &cc);
872
873 keypad(pick->win, true);
874 wrefresh(pick->win2);
875
876 int in_key = 0;
877 while (1) {
878 while (1) {
879 /** ===========================================================
880 Pick Objects Loop
881 =========================================================== */
882
883 set_chyron_key(pick->chyron, 5, "Tab Edit", '\t');
886 if (in_key == 0) {
891
892 /** box display_page_info */
893 ssnprintf(tmp_str, MAXLEN - 1, "Line %d, Page %d/%d",
896 strnz__cat(tmp_str, " ", MAXLEN - 1);
897 tmp_str[21] = '\0';
898 mvwaddstr(pick->box, pick->separator_line, 3, tmp_str);
899 wrefresh(pick->box);
900
901 /** win2 display_field_content */
902 rtrim(accept_s);
903 s = &filler_s[0];
904 e = s + flen;
905 while (s != e)
906 *s++ = ' ';
907 *s = '\0';
908 mvwaddstr(win2, line, col, filler_s);
909 mvwaddstr(win2, line, col, accept_s);
910 pos = col + strlen(accept_s);
911 prev_pos = pos;
912 prev_ptr = accept_s;
913 wmove(win2, line, pos);
914 curs_set(0);
915 wrefresh(win2);
916 /** end display_field_content */
917
918 curs_set(1);
919 wrefresh(win);
921 // 1
923 if (mouse_win == win2 && click_y == 0)
924 break;
925 }
926 switch (in_key) {
927
928 /** KEY_F(1) or 'H' Displays help screen for pick interface */
929 case KEY_F(1):
932 f_insert = false;
936 cchar_t cc = {0};
937 wchar_t wstr[2] = {BW_RAN, L'\0'};
938 setcchar(&cc, wstr, WA_NORMAL, cp_box, nullptr);
939 mvwadd_wch(pick->win2, 0, 0, &cc);
940 wrefresh(pick->win2);
941 in_key = 0;
942 continue;
943
944 /** Toggle Select Object */
945 case KEY_F(13):
946 case 't':
947 case ' ':
950 if (pick->select_max > 0 &&
952 return pick->select_cnt;
953 in_key = 0;
954 continue;
955
956 /** 'q', or KEY_F(9) cancel selection and exit picker */
957 case 'q':
958 case KEY_F(9):
960 return -1;
961
962 /** Enter or KEY_F(10) Accepts current selection and exits
963 picker, returning count of selected objects */
964 case KEY_F(10):
965 case '\n':
966 case KEY_ENTER:
968 return pick->select_cnt;
969
970 /** KEY_END Moves selection to last object in list */
971 case KEY_END:
975 int display_tbl_page = pick->tbl_page;
983 if (display_tbl_page != pick->tbl_page)
985 in_key = 0;
986 continue;
987
988 case '\t':
989 in_key = 0;
990 break;
991
992 /** 'h' or KEY_LEFT or Backspace Moves selection to previous
993 object in list */
994 case 'h':
995 case KEY_LEFT:
996 case KEY_BACKSPACE:
997 if (pick->tbl_col == 0) {
998 in_key = 0;
999 continue;
1000 }
1004 if (pick->tbl_col > 0)
1005 pick->tbl_col--;
1008 in_key = 0;
1009 continue;
1010
1011 /** 'j' or KEY_DOWN Moves selection to next object in list */
1012 case 'j':
1013 case KEY_DOWN:
1014 if (pick->tbl_line == pick->tbl_lines - 1) {
1015 break;
1016 }
1022 pick->d_cnt - 1 &&
1027 in_key = 0;
1028 continue;
1029
1030 /** 'k' or KEY_UP Moves selection to previous object in list */
1031 case 'k':
1032 case KEY_UP:
1036 if (pick->tbl_line > 0)
1040 in_key = 0;
1041 continue;
1042
1043 /** 'l' or KEY_RIGHT Moves selection to next object in list */
1044 case 'l':
1045 case KEY_RIGHT:
1046 if (pick->tbl_col == pick->tbl_cols - 1) {
1047 in_key = 0;
1048 continue;
1049 }
1053 /** pick->obj_idx += pick->tbl_lines -> next column */
1057 pick->d_cnt - 1 &&
1059 pick->tbl_col++;
1062 in_key = 0;
1063 continue;
1064
1065 /** KEY_NPAGE or 'Ctrl+f' Moves selection to next page of
1066 objects */
1067 case KEY_NPAGE:
1068 case '\06':
1069 if (pick->tbl_pages == 1) {
1070 in_key = 0;
1071 continue;
1072 }
1073 if (pick->tbl_page < pick->tbl_pages - 1) {
1075 pick->pg_line = 0;
1076 pick->tbl_col = 0;
1077 }
1081 in_key = 0;
1082 continue;
1083
1084 /** KEY_PPAGE or 'Ctrl+b' Moves selection to previous page of
1085 objects */
1086 case KEY_PPAGE:
1087 case '\02':
1088 if (pick->tbl_pages == 1) {
1089 in_key = 0;
1090 continue;
1091 }
1092 if (pick->tbl_page > 0)
1097 in_key = 0;
1098 continue;
1099
1100 /** KEY_HOME Moves selection to first object in list */
1101 case KEY_HOME:
1102 pick->tbl_page = 0;
1103 pick->tbl_line = 0;
1104 pick->tbl_col = 0;
1108 in_key = 0;
1109 continue;
1110
1111 /** KEY_LL (lower left of numeric pad) Moves selection to last
1112 object in list */
1113 case KEY_LL:
1118 in_key = 0;
1119 continue;
1120
1121 /** KEY_MOUSE Handles mouse events for selection and chyron
1122 * key activation */
1123
1124 case KEY_MOUSE:
1125 if (click_y == -1 || click_x == -1)
1126 continue;
1127 if (click_y < pick->y_offset) {
1128 in_key = 0;
1129 continue;
1130 }
1132 pick->y = click_y;
1135 continue;
1138 in_key = KEY_F(13); /** toggle selection on mouse click */
1139 click_y = click_x = -1;
1140 continue;
1141
1142 default:
1143 in_key = 0;
1144 continue;
1145 }
1147 in_key = 0;
1148 break;
1149 }
1150 /** ===============================================================
1151 Line editor loop
1152 =============================================================== */
1153 set_chyron_key(pick->chyron, 5, "Tab Pick", '\t');
1156 while (1) {
1157 if (in_key == 0) {
1159 if (accept_s != nullptr && accept_s[0] != '\0') {
1160 if (match_objects(pick, accept_s) == 0) {
1161 strnz__cpy(field, prev_field, MAXLEN - 1);
1162 pos = prev_pos;
1163 ptr = prev_ptr;
1164 } else {
1166 /** display_page_info */
1167 ssnprintf(tmp_str, MAXLEN - 1, "Line %d, Page %d/%d",
1170 strnz__cat(tmp_str, " ", MAXLEN - 1);
1171 tmp_str[21] = '\0';
1172 mvwaddstr(pick->box, pick->separator_line, 3, tmp_str);
1173 wrefresh(pick->box);
1174 }
1175 }
1176 /** display_field_content */
1177 rtrim(accept_s);
1178 s = &filler_s[0];
1179 e = s + flen;
1180 while (s != e)
1181 *s++ = ' ';
1182 *s = '\0';
1183 mvwaddstr(win2, line, col, filler_s);
1184 mvwaddstr(win2, line, col, accept_s);
1185 // pos = col + strlen(accept_s);
1186 wmove(win2, line, pos);
1187 wrefresh(win);
1188 wrefresh(win2);
1189 // 2
1190 in_key = dxwgetch(win, win2, pick->chyron, -1);
1191 if (mouse_win == win)
1192 break;
1193 if (in_key == KEY_F(13)) {
1194 in_key = 0;
1195 continue;
1196 }
1197 }
1198 strnz__cpy(prev_field, accept_s, MAXLEN - 1);
1199 prev_pos = pos;
1200 prev_ptr = ptr;
1201 switch (in_key) {
1202 case '\n':
1203 case KEY_ENTER:
1204 in_key = 0;
1205 curs_set(0);
1206 break;
1207
1208 /** KEY_IC toggles insert mode */
1209 /** Tab toggles between windows */
1210 case KEY_BTAB:
1211 case KEY_UP:
1212 case '\t':
1213 in_key = 0;
1214 curs_set(0);
1215 break;
1216
1217 case KEY_F(1):
1218 return (in_key);
1219
1220 /** KEY_F(9) Cancels the current operation */
1221 case KEY_BREAK:
1222 case KEY_F(9):
1223 in_key = KEY_F(9);
1224 return (in_key);
1225
1226 /** KEY_F(10) is the default key for accepting the field */
1227 case KEY_F(10):
1228 return (in_key);
1229
1230 case KEY_END:
1231 case Ctrl('e'):
1232 while (*ptr != '\0')
1233 ptr++;
1234 pos = col + (ptr - fstart);
1235 in_key = 0;
1236 continue;
1237
1238 case KEY_IC:
1239 if (f_insert) {
1240 f_insert = FALSE;
1242 cp_nt_rev);
1243 } else {
1244 f_insert = TRUE;
1247 }
1250 in_key = 0;
1251 continue;
1252
1253 /** KEY_DC deletes character at cursor */
1254 case KEY_DC:
1255 s = ptr + 1;
1256 d = ptr;
1257 while (*s != '\0')
1258 *d++ = *s++;
1259 *d = '\0';
1260 str_end = d;
1261 f_insert = FALSE;
1262 in_key = 0;
1263 continue;
1264
1265 /** KEY_HOME moves cursor to start of field */
1266 case KEY_HOME:
1267 case Ctrl('a'):
1268 ptr = fstart;
1269 pos = col;
1270 in_key = 0;
1271 continue;
1272
1273 /** KEY_BACKSPACE deletes character before cursor */
1274 case KEY_BACKSPACE:
1275 if (ptr > fstart) {
1276 ptr--;
1277 pos--;
1278 } else {
1279 in_key = 0;
1280 continue;
1281 }
1282 s = ptr + 1;
1283 d = ptr;
1284 while (*s != '\0')
1285 *d++ = *s++;
1286 *d = '\0';
1287 str_end = d;
1288 if (ptr == fstart) {
1289 match_objects(pick, accept_s);
1291 ssnprintf(tmp_str, MAXLEN - 1, "Line %d, Page %d/%d",
1294 strnz__cat(tmp_str, " ", MAXLEN - 1);
1295 tmp_str[21] = '\0';
1296 mvwaddstr(pick->box, pick->separator_line, 3, tmp_str);
1297 wrefresh(pick->box);
1298 }
1299 in_key = 0;
1300 continue;
1301
1302 /** KEY_LEFT moves cursor left one character */
1303 case KEY_LEFT:
1304 if (ptr > fstart) {
1305 ptr--;
1306 pos--;
1307 }
1308 in_key = 0;
1309 continue;
1310
1311 /** KEY_RIGHT moves cursor right one character */
1312 case KEY_RIGHT:
1313 if (ptr < fend && ptr <= str_end) {
1314 ptr++;
1315 pos++;
1316 }
1317 in_key = 0;
1318 continue;
1319
1320 /** Handles mouse events for field editing */
1321 case KEY_MOUSE:
1322 if (click_x < col || click_x >= col + flen) {
1323 in_key = 0;
1324 continue;
1325 }
1326 pos = click_x;
1327 fstart = accept_s;
1328 fend = fstart + flen;
1329 str_end = fstart + strlen(fstart);
1330 ptr = fstart + (pos - col);
1331 ptr = min(ptr, str_end);
1332 pos = col + (ptr - fstart);
1333 click_x = -1;
1334 in_key = 0;
1335 continue;
1336
1337 default:
1338 if (in_key < ' ' || in_key > '~') {
1339 in_key = 0;
1340 continue;
1341 }
1342 if (ptr >= fend) {
1343 in_key = 0;
1344 continue;
1345 }
1346 if (f_insert) {
1347 if (str_end < fend) {
1348 s = str_end - 1;
1349 d = str_end;
1350 while (s >= ptr)
1351 *d-- = *s--;
1352 *ptr++ = in_key;
1353 str_end++;
1354 pos++;
1355 }
1356 } else {
1357 if (ptr < fend) {
1358 if (ptr < str_end) {
1359 *ptr++ = in_key;
1360 pos++;
1361 } else if (ptr == str_end) {
1362 *ptr++ = in_key;
1363 *ptr = '\0';
1364 str_end = ptr;
1365 pos++;
1366 }
1367 }
1368 }
1369 in_key = 0;
1370 continue;
1371 }
1372 break;
1373 }
1374 }
1375}
#define P_READ
Definition common.h:47
#define PICK_HELP_FILE
Definition common.h:36
int popup_view(Init *, int, char **, int, int, int, int)
instantiate a view popup window
Definition popups.c:146
#define P_WRITE
Definition common.h:48
Pick * pick
Definition mem.c:46
#define OBJ_MAXLEN
Definition pick.h:16
#define OBJ_MAXCNT
Definition pick.h:17
size_t rtrim(char *)
Trims trailing spaces from string s in place.
Definition futil.c:229
#define MAXARGS
Definition cm.h:30
#define BW_RAN
Definition cm.h:500
int wait_timeout
Definition futil.c:144
#define nullptr
Definition cm.h:25
#define min(x, y)
min macro evaluates two expressions, returning least result
Definition cm.h:56
#define Ctrl(c)
Definition cm.h:34
#define max(a, b)
max macro evaluates two expressions, returning greatest result.
Definition cm.h:49
#define TRUE
Definition iloan.c:19
#define FALSE
Definition iloan.c:18
#define MAXLEN
Definition curskeys.c:15
int tbl_line
Definition pick_engine.c:24
int obj_idx
Definition pick_engine.c:25
int tbl_cols
Definition pick_engine.c:24
char const pagers_editors[12][10]
Definition pick_engine.c:42
int tbl_col
Definition pick_engine.c:24
int pipe_fd[2]
Definition pick_engine.c:40
int tbl_pages
Definition pick_engine.c:24
int calculated_idx
Definition pick_engine.c:25
int pg_lines
Definition pick_engine.c:24
int tbl_page
Definition pick_engine.c:24
int cp_box
Definition dwin.c:147
WINDOW * win
Definition dwin.c:121
WINDOW * win_win[MAXWIN]
Definition dwin.c:122
WINDOW * win_win2[MAXWIN]
Definition dwin.c:123
WINDOW * mouse_win
Definition dwin.c:77
int dxwgetch(WINDOW *win, WINDOW *win2, Chyron *chyron, int n)
Definition dwin.c:1723
int click_x
Definition dwin.c:49
int cp_nt_hl_rev
Definition dwin.c:151
int win_ptr
Definition dwin.c:130
int click_y
Definition dwin.c:48
int cp_nt_rev
Definition dwin.c:149
WINDOW * win_box[MAXWIN]
Definition dwin.c:124
int box2_new(int, int, int, int, char *, bool)
Create a new window with optional box and title.
Definition dwin.c:697
void restore_wins()
Restore all windows after a screen resize.
Definition dwin.c:933
WINDOW * win_del()
Delete the current window and its associated box window.
Definition dwin.c:893
void mvwaddstr_fill(WINDOW *, int, int, char *, int)
For lines shorter than their display area, fill the rest with spaces.
Definition dwin.c:1515
bool wait_destroy(Chyron *)
Destroy the waiting message window and chyron.
Definition dwin.c:1258
bool waitpid_with_timeout(pid_t pid, int timeout)
Wait for a process to finish with a timeout and optional user cancellation.
Definition dwin.c:1603
int wait_continue(WINDOW *, Chyron *, int)
Update the waiting message with remaining time and check for user input.
Definition dwin.c:1271
WINDOW * wait_mk_win(Chyron *, char *)
Display a popup waiting message.
Definition dwin.c:1226
int Perror(char *)
Display a simple error message window or print to stderr.
Definition dwin.c:1162
void abend(int, char *)
Abnormal program termination.
Definition dwin.c:1588
Chyron * wait_mk_chyron()
Create a Chyron struct for the waiting message.
Definition dwin.c:1214
void set_chyron_key(Chyron *, int, char *, int)
Set chyron key with default color pair (cp_nt_rev).
Definition dwin.c:1411
void display_chyron(WINDOW *win, Chyron *chyron, int line, int col)
Display chyron on window.
Definition dwin.c:1476
Chyron * destroy_chyron(Chyron *chyron)
Destroy Chyron structure.
Definition dwin.c:1352
void set_chyron_key_cp(Chyron *, int, char *, int, int)
Set chyron key with color pair (cp).
Definition dwin.c:1388
void compile_chyron(Chyron *)
construct the chyron string from the chyron structure
Definition dwin.c:1436
Chyron * new_chyron()
Create and initialize Chyron structure.
Definition dwin.c:1336
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition futil.c:435
int destroy_argv(int argc, char **argv)
Deallocates memory allocated for argument strings in argv.
Definition futil.c:385
size_t strnz(char *, size_t)
terminates string at New Line, Carriage Return, or max_len
Definition futil.c:506
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
Definition futil.c:311
size_t strnz__cat(char *, const char *, size_t)
safer alternative to strncat
Definition futil.c:464
char * rep_substring(const char *, const char *, const char *)
Replace all occurrences of "tgt_s" in "org_s" with "rep_s".
Definition futil.c:1301
bool base_name(char *, char *)
Returns the base name of a file specification.
Definition futil.c:984
int str_to_args(char **, char *, int)
Converts a string into an array of argument strings.
Definition futil.c:331
Pick * new_pick(Init *, int, char **, int, int)
Create and initialize Pick structure.
Definition mem.c:200
void save_object(Pick *, char *)
Saves a string as an object in the pick structure.
void toggle_object(Pick *)
Toggles the selection state of the currently selected object in pick window.
int picker(Init *, char *field)
Main loop for handling user input and interactions in the pick interface.
int init_pick(Init *, int, char **, int, int)
Initializes pick structure and opens pick input file or pipe.
Definition pick_engine.c:60
void unreverse_object(Pick *)
Unreverses the display of the currently selected object in pick window.
int output_objects(Pick *)
Outputs selected objects to specified output file.
int match_objects(Pick *pick, char *s)
Displays current page of objects in pick window.
void deselect_object(Pick *)
Deselects the currently selected object in pick window.
int read_pick_input(Init *)
Reads pick input from file pointer and saves objects into pick structure.
void reverse_object(Pick *)
Reverses the display of the currently selected object in pick window.
int pick_engine(Init *)
Initializes pick interface, calculates window size and position, and enters picker loop.
void display_page(Pick *)
Displays current page of objects in pick window.
void display_pick_help(Init *)
Displays the help screen for the pick interface using view.
int open_pick_win(Init *)
Initializes the pick window based on the parameters specified in the Pick structure.
int exec_objects(Init *)
Executes specified command with selected objects as arguments.
bool restore_curses_tioctl()
restore_curses_tioctl() - restore curses terminal settings
Definition scriou.c:81
void sig_prog_mode()
Set up signal handlers for interrupt signals.
Definition sig.c:62
char title[MAXLEN]
Definition common.h:120
char mapp_help[MAXLEN]
Definition common.h:137
int begx
Definition common.h:109
SIO * sio
Definition common.h:105
int cols
Definition common.h:107
int begy
Definition common.h:108
int lines
Definition common.h:106
Pick * pick
Definition common.h:173
int l
Definition cm.h:280
char s[MAXLEN]
Definition cm.h:278
int stdout_fd
Definition cm.h:742
int stdin_fd
Definition cm.h:741
int pg_line
Definition pick.h:76
int tbl_lines
Definition pick.h:83
char ** m_object
Definition pick.h:66
int tbl_pages
Definition pick.h:80
int tbl_cols
Definition pick.h:84
bool f_cmd
Definition pick.h:64
WINDOW * win2
Definition pick.h:36
int pg_lines
Definition pick.h:77
int win_width
Definition pick.h:30
WINDOW * box
Definition pick.h:37
int m_idx
Definition pick.h:72
char ** d_object
Definition pick.h:74
char cmd[MAXLEN]
Definition pick.h:51
bool f_help_spec
Definition pick.h:58
FILE * in_fp
Definition pick.h:41
int tbl_col_width
Definition pick.h:86
int d_idx
Definition pick.h:73
bool f_out_spec
Definition pick.h:55
int argc
Definition pick.h:39
int tbl_page
Definition pick.h:81
bool f_multiple_cmd_args
Definition pick.h:59
int d_cnt
Definition pick.h:71
int x
Definition pick.h:34
int separator_line
Definition pick.h:87
bool f_in_pipe
Definition pick.h:56
bool f_selected[OBJ_MAXCNT]
Definition pick.h:60
int select_cnt
Definition pick.h:68
char title[MAXLEN]
Definition pick.h:38
int win_lines
Definition pick.h:29
char help_spec[MAXLEN]
Definition pick.h:48
char in_buf[BUFSIZ]
Definition pick.h:65
int tbl_line
Definition pick.h:82
char ** argv
Definition pick.h:40
int m_cnt
Definition pick.h:70
int select_max
Definition pick.h:69
char in_spec[MAXLEN]
Definition pick.h:46
WINDOW * win
Definition pick.h:35
FILE * out_fp
Definition pick.h:42
int begx
Definition pick.h:32
int y_offset
Definition pick.h:75
Chyron * chyron
Definition pick.h:89
int begy
Definition pick.h:31
int tbl_col
Definition pick.h:85
char provider_cmd[MAXLEN]
Definition pick.h:49
char out_spec[MAXLEN]
Definition pick.h:47
int y
Definition pick.h:33