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