1217309Snwhitehorn/* 2251843Sbapt * $Id: ui_getc.c,v 1.67 2013/03/24 23:53:19 tom Exp $ 3217309Snwhitehorn * 4220749Snwhitehorn * ui_getc.c - user interface glue for getc() 5217309Snwhitehorn * 6251843Sbapt * Copyright 2001-2012,2013 Thomas E. Dickey 7217309Snwhitehorn * 8217309Snwhitehorn * This program is free software; you can redistribute it and/or modify 9217309Snwhitehorn * it under the terms of the GNU Lesser General Public License, version 2.1 10217309Snwhitehorn * as published by the Free Software Foundation. 11217309Snwhitehorn * 12217309Snwhitehorn * This program is distributed in the hope that it will be useful, but 13217309Snwhitehorn * WITHOUT ANY WARRANTY; without even the implied warranty of 14217309Snwhitehorn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15217309Snwhitehorn * Lesser General Public License for more details. 16217309Snwhitehorn * 17217309Snwhitehorn * You should have received a copy of the GNU Lesser General Public 18217309Snwhitehorn * License along with this program; if not, write to 19217309Snwhitehorn * Free Software Foundation, Inc. 20217309Snwhitehorn * 51 Franklin St., Fifth Floor 21217309Snwhitehorn * Boston, MA 02110, USA. 22217309Snwhitehorn */ 23217309Snwhitehorn 24217309Snwhitehorn#include <dialog.h> 25217309Snwhitehorn#include <dlg_keys.h> 26217309Snwhitehorn 27217309Snwhitehorn#ifdef NEED_WCHAR_H 28217309Snwhitehorn#include <wchar.h> 29217309Snwhitehorn#endif 30217309Snwhitehorn 31217309Snwhitehorn#if TIME_WITH_SYS_TIME 32217309Snwhitehorn# include <sys/time.h> 33217309Snwhitehorn# include <time.h> 34217309Snwhitehorn#else 35217309Snwhitehorn# if HAVE_SYS_TIME_H 36217309Snwhitehorn# include <sys/time.h> 37217309Snwhitehorn# else 38217309Snwhitehorn# include <time.h> 39217309Snwhitehorn# endif 40217309Snwhitehorn#endif 41217309Snwhitehorn 42217309Snwhitehorn#ifdef HAVE_SYS_WAIT_H 43217309Snwhitehorn#include <sys/wait.h> 44217309Snwhitehorn#endif 45217309Snwhitehorn 46217309Snwhitehorn#ifdef __QNX__ 47217309Snwhitehorn#include <sys/select.h> 48217309Snwhitehorn#endif 49217309Snwhitehorn 50217309Snwhitehorn#ifndef WEXITSTATUS 51217309Snwhitehorn# ifdef HAVE_TYPE_UNIONWAIT 52217309Snwhitehorn# define WEXITSTATUS(status) (status.w_retcode) 53217309Snwhitehorn# else 54217309Snwhitehorn# define WEXITSTATUS(status) (((status) & 0xff00) >> 8) 55217309Snwhitehorn# endif 56217309Snwhitehorn#endif 57217309Snwhitehorn 58217309Snwhitehorn#ifndef WTERMSIG 59217309Snwhitehorn# ifdef HAVE_TYPE_UNIONWAIT 60217309Snwhitehorn# define WTERMSIG(status) (status.w_termsig) 61217309Snwhitehorn# else 62217309Snwhitehorn# define WTERMSIG(status) ((status) & 0x7f) 63217309Snwhitehorn# endif 64217309Snwhitehorn#endif 65217309Snwhitehorn 66217309Snwhitehornvoid 67217309Snwhitehorndlg_add_callback(DIALOG_CALLBACK * p) 68217309Snwhitehorn{ 69217309Snwhitehorn p->next = dialog_state.getc_callbacks; 70217309Snwhitehorn dialog_state.getc_callbacks = p; 71217309Snwhitehorn wtimeout(p->win, WTIMEOUT_VAL); 72217309Snwhitehorn} 73217309Snwhitehorn 74217309Snwhitehorn/* 75217309Snwhitehorn * Like dlg_add_callback(), but providing for cleanup of caller's associated 76217309Snwhitehorn * state. 77217309Snwhitehorn */ 78217309Snwhitehornvoid 79217309Snwhitehorndlg_add_callback_ref(DIALOG_CALLBACK ** p, DIALOG_FREEBACK freeback) 80217309Snwhitehorn{ 81217309Snwhitehorn (*p)->caller = p; 82217309Snwhitehorn (*p)->freeback = freeback; 83217309Snwhitehorn dlg_add_callback(*p); 84217309Snwhitehorn} 85217309Snwhitehorn 86217309Snwhitehornvoid 87217309Snwhitehorndlg_remove_callback(DIALOG_CALLBACK * p) 88217309Snwhitehorn{ 89217309Snwhitehorn DIALOG_CALLBACK *q; 90217309Snwhitehorn 91217309Snwhitehorn if (p->input != 0) { 92217309Snwhitehorn fclose(p->input); 93217309Snwhitehorn if (p->input == dialog_state.pipe_input) 94217309Snwhitehorn dialog_state.pipe_input = 0; 95217309Snwhitehorn p->input = 0; 96217309Snwhitehorn } 97217309Snwhitehorn 98217309Snwhitehorn if (!(p->keep_win)) 99217309Snwhitehorn dlg_del_window(p->win); 100217309Snwhitehorn if ((q = dialog_state.getc_callbacks) == p) { 101217309Snwhitehorn dialog_state.getc_callbacks = p->next; 102217309Snwhitehorn } else { 103217309Snwhitehorn while (q != 0) { 104217309Snwhitehorn if (q->next == p) { 105217309Snwhitehorn q->next = p->next; 106217309Snwhitehorn break; 107217309Snwhitehorn } 108217309Snwhitehorn q = q->next; 109217309Snwhitehorn } 110217309Snwhitehorn } 111217309Snwhitehorn 112217309Snwhitehorn /* handle dlg_add_callback_ref cleanup */ 113217309Snwhitehorn if (p->freeback != 0) 114217309Snwhitehorn p->freeback(p); 115217309Snwhitehorn if (p->caller != 0) 116217309Snwhitehorn *(p->caller) = 0; 117217309Snwhitehorn 118217309Snwhitehorn free(p); 119217309Snwhitehorn} 120217309Snwhitehorn 121217309Snwhitehorn/* 122220749Snwhitehorn * A select() might find more than one input ready for service. Handle them 123220749Snwhitehorn * all. 124217309Snwhitehorn */ 125220749Snwhitehornstatic bool 126220749Snwhitehornhandle_inputs(WINDOW *win) 127220749Snwhitehorn{ 128220749Snwhitehorn bool result = FALSE; 129220749Snwhitehorn DIALOG_CALLBACK *p; 130220749Snwhitehorn DIALOG_CALLBACK *q; 131220749Snwhitehorn int cur_y, cur_x; 132220749Snwhitehorn int state = ERR; 133220749Snwhitehorn 134220749Snwhitehorn getyx(win, cur_y, cur_x); 135220749Snwhitehorn for (p = dialog_state.getc_callbacks, q = 0; p != 0; p = q) { 136220749Snwhitehorn q = p->next; 137220749Snwhitehorn if ((p->handle_input != 0) && p->input_ready) { 138220749Snwhitehorn p->input_ready = FALSE; 139220749Snwhitehorn if (state == ERR) { 140220749Snwhitehorn state = curs_set(0); 141220749Snwhitehorn } 142220749Snwhitehorn if (p->handle_input(p)) { 143220749Snwhitehorn result = TRUE; 144220749Snwhitehorn } 145220749Snwhitehorn } 146220749Snwhitehorn } 147220749Snwhitehorn if (result) { 148220749Snwhitehorn (void) wmove(win, cur_y, cur_x); /* Restore cursor position */ 149220749Snwhitehorn wrefresh(win); 150220749Snwhitehorn curs_set(state); 151220749Snwhitehorn } 152220749Snwhitehorn return result; 153220749Snwhitehorn} 154220749Snwhitehorn 155220749Snwhitehornstatic bool 156220749Snwhitehornmay_handle_inputs(void) 157220749Snwhitehorn{ 158220749Snwhitehorn bool result = FALSE; 159220749Snwhitehorn 160220749Snwhitehorn DIALOG_CALLBACK *p; 161220749Snwhitehorn 162220749Snwhitehorn for (p = dialog_state.getc_callbacks; p != 0; p = p->next) { 163220749Snwhitehorn if (p->input != 0) { 164220749Snwhitehorn result = TRUE; 165220749Snwhitehorn break; 166220749Snwhitehorn } 167220749Snwhitehorn } 168220749Snwhitehorn 169220749Snwhitehorn return result; 170220749Snwhitehorn} 171220749Snwhitehorn 172220749Snwhitehorn/* 173220749Snwhitehorn * Check any any inputs registered via callbacks, to see if there is any input 174220749Snwhitehorn * available. If there is, return a file-descriptor which should be read. 175220749Snwhitehorn * Otherwise, return -1. 176220749Snwhitehorn */ 177217309Snwhitehornstatic int 178220749Snwhitehorncheck_inputs(void) 179217309Snwhitehorn{ 180220749Snwhitehorn DIALOG_CALLBACK *p; 181217309Snwhitehorn fd_set read_fds; 182217309Snwhitehorn struct timeval test; 183220749Snwhitehorn int last_fd = -1; 184220749Snwhitehorn int fd; 185220749Snwhitehorn int found; 186220749Snwhitehorn int result = -1; 187217309Snwhitehorn 188220749Snwhitehorn if ((p = dialog_state.getc_callbacks) != 0) { 189220749Snwhitehorn FD_ZERO(&read_fds); 190217309Snwhitehorn 191220749Snwhitehorn while (p != 0) { 192220749Snwhitehorn p->input_ready = FALSE; 193220749Snwhitehorn if (p->input != 0 && (fd = fileno(p->input)) >= 0) { 194220749Snwhitehorn FD_SET(fd, &read_fds); 195220749Snwhitehorn if (last_fd < fd) 196220749Snwhitehorn last_fd = fd; 197220749Snwhitehorn } 198220749Snwhitehorn p = p->next; 199220749Snwhitehorn } 200220749Snwhitehorn 201220749Snwhitehorn test.tv_sec = 0; 202220749Snwhitehorn test.tv_usec = WTIMEOUT_VAL * 1000; 203220749Snwhitehorn found = select(last_fd + 1, &read_fds, 204220749Snwhitehorn (fd_set *) 0, 205220749Snwhitehorn (fd_set *) 0, 206220749Snwhitehorn &test); 207220749Snwhitehorn 208220749Snwhitehorn if (found > 0) { 209220749Snwhitehorn for (p = dialog_state.getc_callbacks; p != 0; p = p->next) { 210220749Snwhitehorn if (p->input != 0 211220749Snwhitehorn && (fd = fileno(p->input)) >= 0 212220749Snwhitehorn && FD_ISSET(fd, &read_fds)) { 213220749Snwhitehorn p->input_ready = TRUE; 214220749Snwhitehorn result = fd; 215220749Snwhitehorn } 216220749Snwhitehorn } 217220749Snwhitehorn } 218220749Snwhitehorn } 219220749Snwhitehorn 220220749Snwhitehorn return result; 221217309Snwhitehorn} 222217309Snwhitehorn 223217309Snwhitehornint 224217309Snwhitehorndlg_getc_callbacks(int ch, int fkey, int *result) 225217309Snwhitehorn{ 226217309Snwhitehorn int code = FALSE; 227217309Snwhitehorn DIALOG_CALLBACK *p, *q; 228217309Snwhitehorn 229217309Snwhitehorn if ((p = dialog_state.getc_callbacks) != 0) { 230220749Snwhitehorn if (check_inputs() >= 0) { 231220749Snwhitehorn do { 232220749Snwhitehorn q = p->next; 233220749Snwhitehorn if (p->input_ready) { 234220749Snwhitehorn if (!(p->handle_getc(p, ch, fkey, result))) { 235220749Snwhitehorn dlg_remove_callback(p); 236220749Snwhitehorn } 237217309Snwhitehorn } 238220749Snwhitehorn } while ((p = q) != 0); 239220749Snwhitehorn } 240217309Snwhitehorn code = (dialog_state.getc_callbacks != 0); 241217309Snwhitehorn } 242217309Snwhitehorn return code; 243217309Snwhitehorn} 244217309Snwhitehorn 245217309Snwhitehornstatic void 246217309Snwhitehorndlg_raise_window(WINDOW *win) 247217309Snwhitehorn{ 248217309Snwhitehorn touchwin(win); 249217309Snwhitehorn wmove(win, getcury(win), getcurx(win)); 250217309Snwhitehorn wnoutrefresh(win); 251217309Snwhitehorn doupdate(); 252217309Snwhitehorn} 253217309Snwhitehorn 254217309Snwhitehorn/* 255217309Snwhitehorn * This is a work-around for the case where we actually need the wide-character 256217309Snwhitehorn * code versus a byte stream. 257217309Snwhitehorn */ 258217309Snwhitehornstatic int last_getc = ERR; 259217309Snwhitehorn 260217309Snwhitehorn#ifdef USE_WIDE_CURSES 261217309Snwhitehornstatic char last_getc_bytes[80]; 262217309Snwhitehornstatic int have_last_getc; 263217309Snwhitehornstatic int used_last_getc; 264217309Snwhitehorn#endif 265217309Snwhitehorn 266217309Snwhitehornint 267217309Snwhitehorndlg_last_getc(void) 268217309Snwhitehorn{ 269217309Snwhitehorn#ifdef USE_WIDE_CURSES 270217309Snwhitehorn if (used_last_getc != 1) 271217309Snwhitehorn return ERR; /* not really an error... */ 272217309Snwhitehorn#endif 273217309Snwhitehorn return last_getc; 274217309Snwhitehorn} 275217309Snwhitehorn 276217309Snwhitehornvoid 277217309Snwhitehorndlg_flush_getc(void) 278217309Snwhitehorn{ 279217309Snwhitehorn last_getc = ERR; 280217309Snwhitehorn#ifdef USE_WIDE_CURSES 281217309Snwhitehorn have_last_getc = 0; 282217309Snwhitehorn used_last_getc = 0; 283217309Snwhitehorn#endif 284217309Snwhitehorn} 285217309Snwhitehorn 286217309Snwhitehorn/* 287251843Sbapt * Report the last key entered by the user. The 'mode' parameter controls 288251843Sbapt * the way it is separated from other results: 289251843Sbapt * -2 (no separator) 290251843Sbapt * -1 (separator after the key name) 291251843Sbapt * 0 (separator is optionally before the key name) 292251843Sbapt * 1 (same as -1) 293251843Sbapt */ 294251843Sbaptvoid 295251843Sbaptdlg_add_last_key(int mode) 296251843Sbapt{ 297251843Sbapt if (dialog_vars.last_key) { 298251843Sbapt if (mode >= 0) { 299251843Sbapt if (mode > 0) { 300251843Sbapt dlg_add_last_key(-1); 301251843Sbapt } else { 302251843Sbapt if (dlg_need_separator()) 303251843Sbapt dlg_add_separator(); 304251843Sbapt dlg_add_last_key(-2); 305251843Sbapt } 306251843Sbapt } else { 307251843Sbapt char temp[80]; 308251843Sbapt sprintf(temp, "%d", last_getc); 309251843Sbapt dlg_add_string(temp); 310251843Sbapt if (mode == -1) 311251843Sbapt dlg_add_separator(); 312251843Sbapt } 313251843Sbapt } 314251843Sbapt} 315251843Sbapt 316251843Sbapt/* 317217309Snwhitehorn * Check if the stream has been unexpectedly closed, returning false in that 318217309Snwhitehorn * case. 319217309Snwhitehorn */ 320217309Snwhitehornstatic bool 321217309Snwhitehornvalid_file(FILE *fp) 322217309Snwhitehorn{ 323217309Snwhitehorn bool code = FALSE; 324217309Snwhitehorn int fd = fileno(fp); 325217309Snwhitehorn 326217309Snwhitehorn if (fd >= 0) { 327251843Sbapt if (fcntl(fd, F_GETFL, 0) >= 0) { 328217309Snwhitehorn code = TRUE; 329217309Snwhitehorn } 330217309Snwhitehorn } 331217309Snwhitehorn return code; 332217309Snwhitehorn} 333217309Snwhitehorn 334220749Snwhitehornstatic int 335220749Snwhitehornreally_getch(WINDOW *win, int *fkey) 336220749Snwhitehorn{ 337220749Snwhitehorn int ch; 338220749Snwhitehorn#ifdef USE_WIDE_CURSES 339220749Snwhitehorn int code; 340220749Snwhitehorn mbstate_t state; 341220749Snwhitehorn wchar_t my_wchar; 342220749Snwhitehorn wint_t my_wint; 343220749Snwhitehorn 344220749Snwhitehorn /* 345220749Snwhitehorn * We get a wide character, translate it to multibyte form to avoid 346220749Snwhitehorn * having to change the rest of the code to use wide-characters. 347220749Snwhitehorn */ 348220749Snwhitehorn if (used_last_getc >= have_last_getc) { 349220749Snwhitehorn used_last_getc = 0; 350220749Snwhitehorn have_last_getc = 0; 351220749Snwhitehorn ch = ERR; 352220749Snwhitehorn *fkey = 0; 353220749Snwhitehorn code = wget_wch(win, &my_wint); 354220749Snwhitehorn my_wchar = (wchar_t) my_wint; 355220749Snwhitehorn switch (code) { 356220749Snwhitehorn case KEY_CODE_YES: 357220749Snwhitehorn ch = *fkey = my_wchar; 358220749Snwhitehorn last_getc = my_wchar; 359220749Snwhitehorn break; 360220749Snwhitehorn case OK: 361220749Snwhitehorn memset(&state, 0, sizeof(state)); 362220749Snwhitehorn have_last_getc = (int) wcrtomb(last_getc_bytes, my_wchar, &state); 363220749Snwhitehorn if (have_last_getc < 0) { 364220749Snwhitehorn have_last_getc = used_last_getc = 0; 365220749Snwhitehorn last_getc_bytes[0] = (char) my_wchar; 366220749Snwhitehorn } 367220749Snwhitehorn ch = (int) CharOf(last_getc_bytes[used_last_getc++]); 368220749Snwhitehorn last_getc = my_wchar; 369220749Snwhitehorn break; 370220749Snwhitehorn case ERR: 371220749Snwhitehorn ch = ERR; 372220749Snwhitehorn last_getc = ERR; 373220749Snwhitehorn break; 374220749Snwhitehorn default: 375220749Snwhitehorn break; 376220749Snwhitehorn } 377220749Snwhitehorn } else { 378220749Snwhitehorn ch = (int) CharOf(last_getc_bytes[used_last_getc++]); 379220749Snwhitehorn } 380220749Snwhitehorn#else 381220749Snwhitehorn ch = wgetch(win); 382220749Snwhitehorn last_getc = ch; 383220749Snwhitehorn *fkey = (ch > KEY_MIN && ch < KEY_MAX); 384220749Snwhitehorn#endif 385220749Snwhitehorn return ch; 386220749Snwhitehorn} 387220749Snwhitehorn 388220749Snwhitehornstatic DIALOG_CALLBACK * 389220749Snwhitehornnext_callback(DIALOG_CALLBACK * p) 390220749Snwhitehorn{ 391220749Snwhitehorn if ((p = dialog_state.getc_redirect) != 0) { 392220749Snwhitehorn p = p->next; 393220749Snwhitehorn } else { 394220749Snwhitehorn p = dialog_state.getc_callbacks; 395220749Snwhitehorn } 396220749Snwhitehorn return p; 397220749Snwhitehorn} 398220749Snwhitehorn 399220749Snwhitehornstatic DIALOG_CALLBACK * 400220749Snwhitehornprev_callback(DIALOG_CALLBACK * p) 401220749Snwhitehorn{ 402220749Snwhitehorn DIALOG_CALLBACK *q; 403220749Snwhitehorn 404220749Snwhitehorn if ((p = dialog_state.getc_redirect) != 0) { 405220749Snwhitehorn if (p == dialog_state.getc_callbacks) { 406220749Snwhitehorn for (p = dialog_state.getc_callbacks; p->next != 0; p = p->next) ; 407220749Snwhitehorn } else { 408220749Snwhitehorn for (q = dialog_state.getc_callbacks; q->next != p; q = q->next) ; 409220749Snwhitehorn p = q; 410220749Snwhitehorn } 411220749Snwhitehorn } else { 412220749Snwhitehorn p = dialog_state.getc_callbacks; 413220749Snwhitehorn } 414220749Snwhitehorn return p; 415220749Snwhitehorn} 416220749Snwhitehorn 417224014Snwhitehorn#define isBeforeChr(chr) ((chr) == before_chr && !before_fkey) 418224014Snwhitehorn#define isBeforeFkey(chr) ((chr) == before_chr && before_fkey) 419224014Snwhitehorn 420217309Snwhitehorn/* 421217309Snwhitehorn * Read a character from the given window. Handle repainting here (to simplify 422217309Snwhitehorn * things in the calling application). Also, if input-callback(s) are set up, 423217309Snwhitehorn * poll the corresponding files and handle the updates, e.g., for displaying a 424217309Snwhitehorn * tailbox. 425217309Snwhitehorn */ 426217309Snwhitehornint 427217309Snwhitehorndlg_getc(WINDOW *win, int *fkey) 428217309Snwhitehorn{ 429217309Snwhitehorn WINDOW *save_win = win; 430217309Snwhitehorn int ch = ERR; 431224014Snwhitehorn int before_chr; 432224014Snwhitehorn int before_fkey; 433217309Snwhitehorn int result; 434217309Snwhitehorn bool done = FALSE; 435217309Snwhitehorn bool literal = FALSE; 436220749Snwhitehorn DIALOG_CALLBACK *p = 0; 437220749Snwhitehorn int interval = (dialog_vars.timeout_secs * 1000); 438217309Snwhitehorn time_t expired = time((time_t *) 0) + dialog_vars.timeout_secs; 439217309Snwhitehorn time_t current; 440217309Snwhitehorn 441220749Snwhitehorn if (may_handle_inputs()) 442217309Snwhitehorn wtimeout(win, WTIMEOUT_VAL); 443217309Snwhitehorn else if (interval > 0) 444217309Snwhitehorn wtimeout(win, interval); 445217309Snwhitehorn 446217309Snwhitehorn while (!done) { 447224014Snwhitehorn bool handle_others = FALSE; 448224014Snwhitehorn 449217309Snwhitehorn /* 450220749Snwhitehorn * If there was no pending file-input, check the keyboard. 451217309Snwhitehorn */ 452220749Snwhitehorn ch = really_getch(win, fkey); 453217309Snwhitehorn if (literal) { 454217309Snwhitehorn done = TRUE; 455217309Snwhitehorn continue; 456217309Snwhitehorn } 457217309Snwhitehorn 458224014Snwhitehorn before_chr = ch; 459224014Snwhitehorn before_fkey = *fkey; 460224014Snwhitehorn 461217309Snwhitehorn ch = dlg_lookup_key(win, ch, fkey); 462217309Snwhitehorn dlg_trace_chr(ch, *fkey); 463217309Snwhitehorn 464217309Snwhitehorn current = time((time_t *) 0); 465217309Snwhitehorn 466224014Snwhitehorn /* 467224014Snwhitehorn * If we acquired a fkey value, then it is one of dialog's builtin 468224014Snwhitehorn * codes such as DLGK_HELPFILE. 469224014Snwhitehorn */ 470224014Snwhitehorn if (!*fkey || *fkey != before_fkey) { 471224014Snwhitehorn switch (ch) { 472224014Snwhitehorn case CHR_LITERAL: 473251843Sbapt literal = TRUE; 474251843Sbapt keypad(win, FALSE); 475251843Sbapt continue; 476224014Snwhitehorn case CHR_REPAINT: 477224014Snwhitehorn (void) touchwin(win); 478224014Snwhitehorn (void) wrefresh(curscr); 479224014Snwhitehorn break; 480224014Snwhitehorn case ERR: /* wtimeout() in effect; check for file I/O */ 481224014Snwhitehorn if (interval > 0 482224014Snwhitehorn && current >= expired) { 483224014Snwhitehorn dlg_exiterr("timeout"); 484224014Snwhitehorn } 485224014Snwhitehorn if (!valid_file(stdin) 486224014Snwhitehorn || !valid_file(dialog_state.screen_output)) { 487224014Snwhitehorn ch = ESC; 488220749Snwhitehorn done = TRUE; 489224014Snwhitehorn } else if (check_inputs()) { 490224014Snwhitehorn if (handle_inputs(win)) 491224014Snwhitehorn dlg_raise_window(win); 492224014Snwhitehorn else 493224014Snwhitehorn done = TRUE; 494217309Snwhitehorn } else { 495224014Snwhitehorn done = (interval <= 0); 496217309Snwhitehorn } 497217309Snwhitehorn break; 498224014Snwhitehorn case DLGK_HELPFILE: 499224014Snwhitehorn if (dialog_vars.help_file) { 500224014Snwhitehorn int yold, xold; 501224014Snwhitehorn getyx(win, yold, xold); 502224014Snwhitehorn dialog_helpfile("HELP", dialog_vars.help_file, 0, 0); 503224014Snwhitehorn dlg_raise_window(win); 504224014Snwhitehorn wmove(win, yold, xold); 505224014Snwhitehorn } 506224014Snwhitehorn continue; 507224014Snwhitehorn case DLGK_FIELD_PREV: 508224014Snwhitehorn /* FALLTHRU */ 509224014Snwhitehorn case KEY_BTAB: 510224014Snwhitehorn /* FALLTHRU */ 511224014Snwhitehorn case DLGK_FIELD_NEXT: 512224014Snwhitehorn /* FALLTHRU */ 513224014Snwhitehorn case TAB: 514224014Snwhitehorn /* Handle tab/backtab as a special case for traversing between 515224014Snwhitehorn * the nominal "current" window, and other windows having 516224014Snwhitehorn * callbacks. If the nominal (control) window closes, we'll 517224014Snwhitehorn * close the windows with callbacks. 518224014Snwhitehorn */ 519224014Snwhitehorn if (dialog_state.getc_callbacks != 0 && 520224014Snwhitehorn (isBeforeChr(TAB) || 521224014Snwhitehorn isBeforeFkey(KEY_BTAB))) { 522224014Snwhitehorn p = (isBeforeChr(TAB) 523224014Snwhitehorn ? next_callback(p) 524224014Snwhitehorn : prev_callback(p)); 525224014Snwhitehorn if ((dialog_state.getc_redirect = p) != 0) { 526224014Snwhitehorn win = p->win; 527224014Snwhitehorn } else { 528224014Snwhitehorn win = save_win; 529224014Snwhitehorn } 530224014Snwhitehorn dlg_raise_window(win); 531224014Snwhitehorn break; 532224014Snwhitehorn } 533224014Snwhitehorn /* FALLTHRU */ 534224014Snwhitehorn default: 535217309Snwhitehorn#ifdef NO_LEAKS 536224014Snwhitehorn if (isBeforeChr(DLG_CTRL('P'))) { 537224014Snwhitehorn /* for testing, ^P closes the connection */ 538224014Snwhitehorn close(0); 539224014Snwhitehorn close(1); 540224014Snwhitehorn close(2); 541224014Snwhitehorn break; 542224014Snwhitehorn } 543224014Snwhitehorn#endif 544224014Snwhitehorn handle_others = TRUE; 545217309Snwhitehorn break; 546224014Snwhitehorn#ifdef HAVE_DLG_TRACE 547224014Snwhitehorn case CHR_TRACE: 548224014Snwhitehorn dlg_trace_win(win); 549224014Snwhitehorn break; 550224014Snwhitehorn#endif 551217309Snwhitehorn } 552224014Snwhitehorn } else { 553224014Snwhitehorn handle_others = TRUE; 554224014Snwhitehorn } 555224014Snwhitehorn 556224014Snwhitehorn if (handle_others) { 557217309Snwhitehorn if ((p = dialog_state.getc_redirect) != 0) { 558217309Snwhitehorn if (!(p->handle_getc(p, ch, *fkey, &result))) { 559251843Sbapt done = (p->win == save_win) && (!p->keep_win); 560217309Snwhitehorn dlg_remove_callback(p); 561217309Snwhitehorn dialog_state.getc_redirect = 0; 562217309Snwhitehorn win = save_win; 563217309Snwhitehorn } 564217309Snwhitehorn } else { 565217309Snwhitehorn done = TRUE; 566217309Snwhitehorn } 567217309Snwhitehorn } 568217309Snwhitehorn } 569217309Snwhitehorn if (literal) 570217309Snwhitehorn keypad(win, TRUE); 571217309Snwhitehorn return ch; 572217309Snwhitehorn} 573217309Snwhitehorn 574217309Snwhitehornstatic void 575217309Snwhitehornfinish_bg(int sig GCC_UNUSED) 576217309Snwhitehorn{ 577217309Snwhitehorn end_dialog(); 578217309Snwhitehorn dlg_exit(DLG_EXIT_ERROR); 579217309Snwhitehorn} 580217309Snwhitehorn 581217309Snwhitehorn/* 582217309Snwhitehorn * If we have callbacks active, purge the list of all that are not marked 583217309Snwhitehorn * to keep in the background. If any remain, run those in a background 584217309Snwhitehorn * process. 585217309Snwhitehorn */ 586217309Snwhitehornvoid 587217309Snwhitehorndlg_killall_bg(int *retval) 588217309Snwhitehorn{ 589217309Snwhitehorn DIALOG_CALLBACK *cb; 590217309Snwhitehorn int pid; 591217309Snwhitehorn#ifdef HAVE_TYPE_UNIONWAIT 592217309Snwhitehorn union wait wstatus; 593217309Snwhitehorn#else 594217309Snwhitehorn int wstatus; 595217309Snwhitehorn#endif 596217309Snwhitehorn 597217309Snwhitehorn if ((cb = dialog_state.getc_callbacks) != 0) { 598217309Snwhitehorn while (cb != 0) { 599217309Snwhitehorn if (cb->keep_bg) { 600217309Snwhitehorn cb = cb->next; 601217309Snwhitehorn } else { 602217309Snwhitehorn dlg_remove_callback(cb); 603217309Snwhitehorn cb = dialog_state.getc_callbacks; 604217309Snwhitehorn } 605217309Snwhitehorn } 606217309Snwhitehorn if (dialog_state.getc_callbacks != 0) { 607217309Snwhitehorn 608217309Snwhitehorn refresh(); 609217309Snwhitehorn fflush(stdout); 610217309Snwhitehorn fflush(stderr); 611217309Snwhitehorn reset_shell_mode(); 612217309Snwhitehorn if ((pid = fork()) != 0) { 613217309Snwhitehorn _exit(pid > 0 ? DLG_EXIT_OK : DLG_EXIT_ERROR); 614217309Snwhitehorn } else if (pid == 0) { /* child */ 615217309Snwhitehorn if ((pid = fork()) != 0) { 616217309Snwhitehorn /* 617217309Snwhitehorn * Echo the process-id of the grandchild so a shell script 618217309Snwhitehorn * can read that, and kill that process. We'll wait around 619217309Snwhitehorn * until then. Our parent has already left, leaving us 620217309Snwhitehorn * temporarily orphaned. 621217309Snwhitehorn */ 622217309Snwhitehorn if (pid > 0) { /* parent */ 623217309Snwhitehorn fprintf(stderr, "%d\n", pid); 624217309Snwhitehorn fflush(stderr); 625217309Snwhitehorn } 626217309Snwhitehorn /* wait for child */ 627217309Snwhitehorn#ifdef HAVE_WAITPID 628217309Snwhitehorn while (-1 == waitpid(pid, &wstatus, 0)) { 629217309Snwhitehorn#ifdef EINTR 630217309Snwhitehorn if (errno == EINTR) 631217309Snwhitehorn continue; 632217309Snwhitehorn#endif /* EINTR */ 633217309Snwhitehorn#ifdef ERESTARTSYS 634217309Snwhitehorn if (errno == ERESTARTSYS) 635217309Snwhitehorn continue; 636217309Snwhitehorn#endif /* ERESTARTSYS */ 637217309Snwhitehorn break; 638217309Snwhitehorn } 639217309Snwhitehorn#else 640217309Snwhitehorn while (wait(&wstatus) != pid) /* do nothing */ 641217309Snwhitehorn ; 642217309Snwhitehorn#endif 643217309Snwhitehorn _exit(WEXITSTATUS(wstatus)); 644217309Snwhitehorn } else if (pid == 0) { 645217309Snwhitehorn if (!dialog_vars.cant_kill) 646217309Snwhitehorn (void) signal(SIGHUP, finish_bg); 647217309Snwhitehorn (void) signal(SIGINT, finish_bg); 648217309Snwhitehorn (void) signal(SIGQUIT, finish_bg); 649217309Snwhitehorn (void) signal(SIGSEGV, finish_bg); 650217309Snwhitehorn while (dialog_state.getc_callbacks != 0) { 651217309Snwhitehorn int fkey = 0; 652217309Snwhitehorn dlg_getc_callbacks(ERR, fkey, retval); 653217309Snwhitehorn napms(1000); 654217309Snwhitehorn } 655217309Snwhitehorn } 656217309Snwhitehorn } 657217309Snwhitehorn } 658217309Snwhitehorn } 659217309Snwhitehorn} 660