xref: /dragonfly/contrib/dialog/ui_getc.c (revision a8e38dc0)
15382d832SPeter Avalos /*
2*a8e38dc0SAntonio Huete Jimenez  *  $Id: ui_getc.c,v 1.84 2022/04/08 21:01:51 tom Exp $
35382d832SPeter Avalos  *
45382d832SPeter Avalos  *  ui_getc.c - user interface glue for getc()
55382d832SPeter Avalos  *
6*a8e38dc0SAntonio Huete Jimenez  *  Copyright 2001-2021,2022	Thomas E. Dickey
75382d832SPeter Avalos  *
85382d832SPeter Avalos  *  This program is free software; you can redistribute it and/or modify
95382d832SPeter Avalos  *  it under the terms of the GNU Lesser General Public License, version 2.1
105382d832SPeter Avalos  *  as published by the Free Software Foundation.
115382d832SPeter Avalos  *
125382d832SPeter Avalos  *  This program is distributed in the hope that it will be useful, but
135382d832SPeter Avalos  *  WITHOUT ANY WARRANTY; without even the implied warranty of
145382d832SPeter Avalos  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
155382d832SPeter Avalos  *  Lesser General Public License for more details.
165382d832SPeter Avalos  *
175382d832SPeter Avalos  *  You should have received a copy of the GNU Lesser General Public
185382d832SPeter Avalos  *  License along with this program; if not, write to
195382d832SPeter Avalos  *	Free Software Foundation, Inc.
205382d832SPeter Avalos  *	51 Franklin St., Fifth Floor
215382d832SPeter Avalos  *	Boston, MA 02110, USA.
225382d832SPeter Avalos  */
235382d832SPeter Avalos 
24*a8e38dc0SAntonio Huete Jimenez #include <dlg_internals.h>
255382d832SPeter Avalos #include <dlg_keys.h>
265382d832SPeter Avalos 
275382d832SPeter Avalos #ifdef HAVE_SYS_WAIT_H
285382d832SPeter Avalos #include <sys/wait.h>
295382d832SPeter Avalos #endif
305382d832SPeter Avalos 
315382d832SPeter Avalos #ifdef __QNX__
325382d832SPeter Avalos #include <sys/select.h>
335382d832SPeter Avalos #endif
345382d832SPeter Avalos 
355382d832SPeter Avalos #ifndef WEXITSTATUS
365382d832SPeter Avalos # ifdef HAVE_TYPE_UNIONWAIT
375382d832SPeter Avalos #  define	WEXITSTATUS(status)	(status.w_retcode)
385382d832SPeter Avalos # else
395382d832SPeter Avalos #  define	WEXITSTATUS(status)	(((status) & 0xff00) >> 8)
405382d832SPeter Avalos # endif
415382d832SPeter Avalos #endif
425382d832SPeter Avalos 
435382d832SPeter Avalos #ifndef WTERMSIG
445382d832SPeter Avalos # ifdef HAVE_TYPE_UNIONWAIT
455382d832SPeter Avalos #  define	WTERMSIG(status)	(status.w_termsig)
465382d832SPeter Avalos # else
475382d832SPeter Avalos #  define	WTERMSIG(status)	((status) & 0x7f)
485382d832SPeter Avalos # endif
495382d832SPeter Avalos #endif
505382d832SPeter Avalos 
515382d832SPeter Avalos void
dlg_add_callback(DIALOG_CALLBACK * p)525382d832SPeter Avalos dlg_add_callback(DIALOG_CALLBACK * p)
535382d832SPeter Avalos {
545382d832SPeter Avalos     p->next = dialog_state.getc_callbacks;
555382d832SPeter Avalos     dialog_state.getc_callbacks = p;
565940c9abSDaniel Fojt     dlg_set_timeout(p->win, TRUE);
575382d832SPeter Avalos }
585382d832SPeter Avalos 
595382d832SPeter Avalos /*
605382d832SPeter Avalos  * Like dlg_add_callback(), but providing for cleanup of caller's associated
615382d832SPeter Avalos  * state.
625382d832SPeter Avalos  */
635382d832SPeter Avalos void
dlg_add_callback_ref(DIALOG_CALLBACK ** p,DIALOG_FREEBACK freeback)645382d832SPeter Avalos dlg_add_callback_ref(DIALOG_CALLBACK ** p, DIALOG_FREEBACK freeback)
655382d832SPeter Avalos {
665382d832SPeter Avalos     (*p)->caller = p;
675382d832SPeter Avalos     (*p)->freeback = freeback;
685382d832SPeter Avalos     dlg_add_callback(*p);
695382d832SPeter Avalos }
705382d832SPeter Avalos 
715382d832SPeter Avalos void
dlg_remove_callback(DIALOG_CALLBACK * p)725382d832SPeter Avalos dlg_remove_callback(DIALOG_CALLBACK * p)
735382d832SPeter Avalos {
745382d832SPeter Avalos     DIALOG_CALLBACK *q;
755382d832SPeter Avalos 
765382d832SPeter Avalos     if (p->input != 0) {
775940c9abSDaniel Fojt 	FILE *input = p->input;
785940c9abSDaniel Fojt 	fclose(input);
795382d832SPeter Avalos 	if (p->input == dialog_state.pipe_input)
805382d832SPeter Avalos 	    dialog_state.pipe_input = 0;
815940c9abSDaniel Fojt 	/* more than one callback can have the same input */
825940c9abSDaniel Fojt 	for (q = dialog_state.getc_callbacks; q != 0; q = q->next) {
835940c9abSDaniel Fojt 	    if (q->input == input) {
845940c9abSDaniel Fojt 		q->input = 0;
855940c9abSDaniel Fojt 	    }
865940c9abSDaniel Fojt 	}
875382d832SPeter Avalos     }
885382d832SPeter Avalos 
895382d832SPeter Avalos     if (!(p->keep_win))
905382d832SPeter Avalos 	dlg_del_window(p->win);
915382d832SPeter Avalos     if ((q = dialog_state.getc_callbacks) == p) {
925382d832SPeter Avalos 	dialog_state.getc_callbacks = p->next;
935382d832SPeter Avalos     } else {
945382d832SPeter Avalos 	while (q != 0) {
955382d832SPeter Avalos 	    if (q->next == p) {
965382d832SPeter Avalos 		q->next = p->next;
975382d832SPeter Avalos 		break;
985382d832SPeter Avalos 	    }
995382d832SPeter Avalos 	    q = q->next;
1005382d832SPeter Avalos 	}
1015382d832SPeter Avalos     }
1025382d832SPeter Avalos 
1035382d832SPeter Avalos     /* handle dlg_add_callback_ref cleanup */
1045382d832SPeter Avalos     if (p->freeback != 0)
1055382d832SPeter Avalos 	p->freeback(p);
1065382d832SPeter Avalos     if (p->caller != 0)
1075382d832SPeter Avalos 	*(p->caller) = 0;
1085382d832SPeter Avalos 
1095382d832SPeter Avalos     free(p);
1105382d832SPeter Avalos }
1115382d832SPeter Avalos 
1125382d832SPeter Avalos /*
1135382d832SPeter Avalos  * A select() might find more than one input ready for service.  Handle them
1145382d832SPeter Avalos  * all.
1155382d832SPeter Avalos  */
1165382d832SPeter Avalos static bool
handle_inputs(WINDOW * win)1175382d832SPeter Avalos handle_inputs(WINDOW *win)
1185382d832SPeter Avalos {
1195382d832SPeter Avalos     bool result = FALSE;
1205382d832SPeter Avalos     DIALOG_CALLBACK *p;
1215382d832SPeter Avalos     DIALOG_CALLBACK *q;
1225382d832SPeter Avalos     int cur_y, cur_x;
1235382d832SPeter Avalos     int state = ERR;
1245382d832SPeter Avalos 
1255382d832SPeter Avalos     getyx(win, cur_y, cur_x);
1265382d832SPeter Avalos     for (p = dialog_state.getc_callbacks, q = 0; p != 0; p = q) {
1275382d832SPeter Avalos 	q = p->next;
1285382d832SPeter Avalos 	if ((p->handle_input != 0) && p->input_ready) {
1295382d832SPeter Avalos 	    p->input_ready = FALSE;
1305382d832SPeter Avalos 	    if (state == ERR) {
1315382d832SPeter Avalos 		state = curs_set(0);
1325382d832SPeter Avalos 	    }
1335382d832SPeter Avalos 	    if (p->handle_input(p)) {
1345382d832SPeter Avalos 		result = TRUE;
1355382d832SPeter Avalos 	    }
1365382d832SPeter Avalos 	}
1375382d832SPeter Avalos     }
138*a8e38dc0SAntonio Huete Jimenez     if (result && _dlg_find_window(win)) {
1395382d832SPeter Avalos 	(void) wmove(win, cur_y, cur_x);	/* Restore cursor position */
1405382d832SPeter Avalos 	wrefresh(win);
141*a8e38dc0SAntonio Huete Jimenez     } else {
142*a8e38dc0SAntonio Huete Jimenez 	result = FALSE;
1435382d832SPeter Avalos     }
1445940c9abSDaniel Fojt     if (state != ERR)
1455940c9abSDaniel Fojt 	curs_set(state);
1465382d832SPeter Avalos     return result;
1475382d832SPeter Avalos }
1485382d832SPeter Avalos 
1495382d832SPeter Avalos static bool
may_handle_inputs(void)1505382d832SPeter Avalos may_handle_inputs(void)
1515382d832SPeter Avalos {
1525382d832SPeter Avalos     bool result = FALSE;
1535382d832SPeter Avalos 
1545382d832SPeter Avalos     DIALOG_CALLBACK *p;
1555382d832SPeter Avalos 
1565382d832SPeter Avalos     for (p = dialog_state.getc_callbacks; p != 0; p = p->next) {
1575382d832SPeter Avalos 	if (p->input != 0) {
1585382d832SPeter Avalos 	    result = TRUE;
1595382d832SPeter Avalos 	    break;
1605382d832SPeter Avalos 	}
1615382d832SPeter Avalos     }
1625382d832SPeter Avalos 
1635382d832SPeter Avalos     return result;
1645382d832SPeter Avalos }
1655382d832SPeter Avalos 
1665382d832SPeter Avalos /*
1675382d832SPeter Avalos  * Check any any inputs registered via callbacks, to see if there is any input
1685382d832SPeter Avalos  * available.  If there is, return a file-descriptor which should be read.
1695382d832SPeter Avalos  * Otherwise, return -1.
1705382d832SPeter Avalos  */
1715382d832SPeter Avalos static int
check_inputs(void)1725382d832SPeter Avalos check_inputs(void)
1735382d832SPeter Avalos {
1745382d832SPeter Avalos     DIALOG_CALLBACK *p;
1755382d832SPeter Avalos     fd_set read_fds;
1765382d832SPeter Avalos     struct timeval test;
1775382d832SPeter Avalos     int result = -1;
1785382d832SPeter Avalos 
1795382d832SPeter Avalos     if ((p = dialog_state.getc_callbacks) != 0) {
1805940c9abSDaniel Fojt 	int last_fd = -1;
1815940c9abSDaniel Fojt 	int found;
1825940c9abSDaniel Fojt 	int fd;
1835940c9abSDaniel Fojt 
1845382d832SPeter Avalos 	FD_ZERO(&read_fds);
1855382d832SPeter Avalos 
1865382d832SPeter Avalos 	while (p != 0) {
1875940c9abSDaniel Fojt 
1885382d832SPeter Avalos 	    p->input_ready = FALSE;
1895382d832SPeter Avalos 	    if (p->input != 0 && (fd = fileno(p->input)) >= 0) {
1905382d832SPeter Avalos 		FD_SET(fd, &read_fds);
1915382d832SPeter Avalos 		if (last_fd < fd)
1925382d832SPeter Avalos 		    last_fd = fd;
1935382d832SPeter Avalos 	    }
1945382d832SPeter Avalos 	    p = p->next;
1955382d832SPeter Avalos 	}
1965382d832SPeter Avalos 
1975382d832SPeter Avalos 	test.tv_sec = 0;
1985382d832SPeter Avalos 	test.tv_usec = WTIMEOUT_VAL * 1000;
1995382d832SPeter Avalos 	found = select(last_fd + 1, &read_fds,
2005382d832SPeter Avalos 		       (fd_set *) 0,
2015382d832SPeter Avalos 		       (fd_set *) 0,
2025382d832SPeter Avalos 		       &test);
2035382d832SPeter Avalos 
2045382d832SPeter Avalos 	if (found > 0) {
2055382d832SPeter Avalos 	    for (p = dialog_state.getc_callbacks; p != 0; p = p->next) {
2065382d832SPeter Avalos 		if (p->input != 0
2075382d832SPeter Avalos 		    && (fd = fileno(p->input)) >= 0
2085382d832SPeter Avalos 		    && FD_ISSET(fd, &read_fds)) {
2095382d832SPeter Avalos 		    p->input_ready = TRUE;
2105382d832SPeter Avalos 		    result = fd;
2115382d832SPeter Avalos 		}
2125382d832SPeter Avalos 	    }
2135382d832SPeter Avalos 	}
2145382d832SPeter Avalos     }
2155382d832SPeter Avalos 
2165382d832SPeter Avalos     return result;
2175382d832SPeter Avalos }
2185382d832SPeter Avalos 
2195382d832SPeter Avalos int
dlg_getc_callbacks(int ch,int fkey,int * result)2205382d832SPeter Avalos dlg_getc_callbacks(int ch, int fkey, int *result)
2215382d832SPeter Avalos {
2225382d832SPeter Avalos     int code = FALSE;
2235382d832SPeter Avalos     DIALOG_CALLBACK *p, *q;
2245382d832SPeter Avalos 
2255382d832SPeter Avalos     if ((p = dialog_state.getc_callbacks) != 0) {
2265382d832SPeter Avalos 	if (check_inputs() >= 0) {
2275382d832SPeter Avalos 	    do {
2285382d832SPeter Avalos 		q = p->next;
2295382d832SPeter Avalos 		if (p->input_ready) {
2305382d832SPeter Avalos 		    if (!(p->handle_getc(p, ch, fkey, result))) {
2315382d832SPeter Avalos 			dlg_remove_callback(p);
2325382d832SPeter Avalos 		    }
2335382d832SPeter Avalos 		}
2345382d832SPeter Avalos 	    } while ((p = q) != 0);
2355382d832SPeter Avalos 	}
2365382d832SPeter Avalos 	code = (dialog_state.getc_callbacks != 0);
2375382d832SPeter Avalos     }
2385382d832SPeter Avalos     return code;
2395382d832SPeter Avalos }
2405382d832SPeter Avalos 
2415382d832SPeter Avalos static void
dlg_raise_window(WINDOW * win)2425382d832SPeter Avalos dlg_raise_window(WINDOW *win)
2435382d832SPeter Avalos {
244*a8e38dc0SAntonio Huete Jimenez     if (_dlg_find_window(win)) {
2455382d832SPeter Avalos 	touchwin(win);
2465382d832SPeter Avalos 	wmove(win, getcury(win), getcurx(win));
2475382d832SPeter Avalos 	wnoutrefresh(win);
2485382d832SPeter Avalos 	doupdate();
2495382d832SPeter Avalos     }
250*a8e38dc0SAntonio Huete Jimenez }
2515382d832SPeter Avalos 
2525382d832SPeter Avalos /*
2535382d832SPeter Avalos  * This is a work-around for the case where we actually need the wide-character
2545382d832SPeter Avalos  * code versus a byte stream.
2555382d832SPeter Avalos  */
2565382d832SPeter Avalos static int last_getc = ERR;
2575382d832SPeter Avalos 
2585382d832SPeter Avalos #ifdef USE_WIDE_CURSES
2595382d832SPeter Avalos static char last_getc_bytes[80];
2605382d832SPeter Avalos static int have_last_getc;
2615382d832SPeter Avalos static int used_last_getc;
2625382d832SPeter Avalos #endif
2635382d832SPeter Avalos 
2645382d832SPeter Avalos int
dlg_last_getc(void)2655382d832SPeter Avalos dlg_last_getc(void)
2665382d832SPeter Avalos {
2675382d832SPeter Avalos #ifdef USE_WIDE_CURSES
2685382d832SPeter Avalos     if (used_last_getc != 1)
2695382d832SPeter Avalos 	return ERR;		/* not really an error... */
2705382d832SPeter Avalos #endif
2715382d832SPeter Avalos     return last_getc;
2725382d832SPeter Avalos }
2735382d832SPeter Avalos 
2745382d832SPeter Avalos void
dlg_flush_getc(void)2755382d832SPeter Avalos dlg_flush_getc(void)
2765382d832SPeter Avalos {
2775382d832SPeter Avalos     last_getc = ERR;
2785382d832SPeter Avalos #ifdef USE_WIDE_CURSES
2795382d832SPeter Avalos     have_last_getc = 0;
2805382d832SPeter Avalos     used_last_getc = 0;
2815382d832SPeter Avalos #endif
2825382d832SPeter Avalos }
2835382d832SPeter Avalos 
2845382d832SPeter Avalos /*
2851ef6786aSJohn Marino  * Report the last key entered by the user.  The 'mode' parameter controls
2861ef6786aSJohn Marino  * the way it is separated from other results:
2871ef6786aSJohn Marino  * -2 (no separator)
2881ef6786aSJohn Marino  * -1 (separator after the key name)
2891ef6786aSJohn Marino  * 0 (separator is optionally before the key name)
2901ef6786aSJohn Marino  * 1 (same as -1)
2911ef6786aSJohn Marino  */
2921ef6786aSJohn Marino void
dlg_add_last_key(int mode)2931ef6786aSJohn Marino dlg_add_last_key(int mode)
2941ef6786aSJohn Marino {
2951ef6786aSJohn Marino     if (dialog_vars.last_key) {
2961ef6786aSJohn Marino 	if (mode >= 0) {
2971ef6786aSJohn Marino 	    if (mode > 0) {
2981ef6786aSJohn Marino 		dlg_add_last_key(-1);
2991ef6786aSJohn Marino 	    } else {
3001ef6786aSJohn Marino 		if (dlg_need_separator())
3011ef6786aSJohn Marino 		    dlg_add_separator();
3021ef6786aSJohn Marino 		dlg_add_last_key(-2);
3031ef6786aSJohn Marino 	    }
3041ef6786aSJohn Marino 	} else {
3051ef6786aSJohn Marino 	    char temp[80];
3061ef6786aSJohn Marino 	    sprintf(temp, "%d", last_getc);
3075940c9abSDaniel Fojt 	    DLG_TRACE(("# dlg_add_last_key(%s)\n", temp));
3081ef6786aSJohn Marino 	    dlg_add_string(temp);
3091ef6786aSJohn Marino 	    if (mode == -1)
3101ef6786aSJohn Marino 		dlg_add_separator();
3111ef6786aSJohn Marino 	}
3121ef6786aSJohn Marino     }
3131ef6786aSJohn Marino }
3141ef6786aSJohn Marino 
3151ef6786aSJohn Marino /*
3165382d832SPeter Avalos  * Check if the stream has been unexpectedly closed, returning false in that
3175382d832SPeter Avalos  * case.
3185382d832SPeter Avalos  */
3195382d832SPeter Avalos static bool
valid_file(FILE * fp)3205382d832SPeter Avalos valid_file(FILE *fp)
3215382d832SPeter Avalos {
3225382d832SPeter Avalos     bool code = FALSE;
3235382d832SPeter Avalos     int fd = fileno(fp);
3245382d832SPeter Avalos 
3255382d832SPeter Avalos     if (fd >= 0) {
3265382d832SPeter Avalos 	if (fcntl(fd, F_GETFL, 0) >= 0) {
3275382d832SPeter Avalos 	    code = TRUE;
3285382d832SPeter Avalos 	}
3295382d832SPeter Avalos     }
3305382d832SPeter Avalos     return code;
3315382d832SPeter Avalos }
3325382d832SPeter Avalos 
3335382d832SPeter Avalos static int
really_getch(WINDOW * win,int * fkey)3345382d832SPeter Avalos really_getch(WINDOW *win, int *fkey)
3355382d832SPeter Avalos {
3365382d832SPeter Avalos     int ch;
3375382d832SPeter Avalos #ifdef USE_WIDE_CURSES
3385382d832SPeter Avalos     mbstate_t state;
3395382d832SPeter Avalos     wint_t my_wint;
3405382d832SPeter Avalos 
3415382d832SPeter Avalos     /*
3425382d832SPeter Avalos      * We get a wide character, translate it to multibyte form to avoid
3435382d832SPeter Avalos      * having to change the rest of the code to use wide-characters.
3445382d832SPeter Avalos      */
3455382d832SPeter Avalos     if (used_last_getc >= have_last_getc) {
3465940c9abSDaniel Fojt 	int code;
3475940c9abSDaniel Fojt 	wchar_t my_wchar;
3485940c9abSDaniel Fojt 
3495382d832SPeter Avalos 	used_last_getc = 0;
3505382d832SPeter Avalos 	have_last_getc = 0;
3515382d832SPeter Avalos 	ch = ERR;
3525382d832SPeter Avalos 	*fkey = 0;
3535382d832SPeter Avalos 	code = wget_wch(win, &my_wint);
3545382d832SPeter Avalos 	my_wchar = (wchar_t) my_wint;
3555382d832SPeter Avalos 	switch (code) {
3565382d832SPeter Avalos 	case KEY_CODE_YES:
3575382d832SPeter Avalos 	    ch = *fkey = my_wchar;
3585382d832SPeter Avalos 	    last_getc = my_wchar;
3595382d832SPeter Avalos 	    break;
3605382d832SPeter Avalos 	case OK:
3615382d832SPeter Avalos 	    memset(&state, 0, sizeof(state));
3625382d832SPeter Avalos 	    have_last_getc = (int) wcrtomb(last_getc_bytes, my_wchar, &state);
3635382d832SPeter Avalos 	    if (have_last_getc < 0) {
3645382d832SPeter Avalos 		have_last_getc = used_last_getc = 0;
3655382d832SPeter Avalos 		last_getc_bytes[0] = (char) my_wchar;
3665382d832SPeter Avalos 	    }
367*a8e38dc0SAntonio Huete Jimenez 	    ch = (int) UCH(last_getc_bytes[used_last_getc++]);
3685382d832SPeter Avalos 	    last_getc = my_wchar;
3695382d832SPeter Avalos 	    break;
3705382d832SPeter Avalos 	case ERR:
3715382d832SPeter Avalos 	    ch = ERR;
3725382d832SPeter Avalos 	    last_getc = ERR;
3735382d832SPeter Avalos 	    break;
3745382d832SPeter Avalos 	default:
3755382d832SPeter Avalos 	    break;
3765382d832SPeter Avalos 	}
3775382d832SPeter Avalos     } else {
378*a8e38dc0SAntonio Huete Jimenez 	ch = (int) UCH(last_getc_bytes[used_last_getc++]);
3795382d832SPeter Avalos     }
3805382d832SPeter Avalos #else
3815382d832SPeter Avalos     ch = wgetch(win);
3825382d832SPeter Avalos     last_getc = ch;
3835382d832SPeter Avalos     *fkey = (ch > KEY_MIN && ch < KEY_MAX);
3845382d832SPeter Avalos #endif
3855382d832SPeter Avalos     return ch;
3865382d832SPeter Avalos }
3875382d832SPeter Avalos 
3885382d832SPeter Avalos static DIALOG_CALLBACK *
next_callback(DIALOG_CALLBACK * p)3895382d832SPeter Avalos next_callback(DIALOG_CALLBACK * p)
3905382d832SPeter Avalos {
3915382d832SPeter Avalos     if ((p = dialog_state.getc_redirect) != 0) {
3925382d832SPeter Avalos 	p = p->next;
3935382d832SPeter Avalos     } else {
3945382d832SPeter Avalos 	p = dialog_state.getc_callbacks;
3955382d832SPeter Avalos     }
3965382d832SPeter Avalos     return p;
3975382d832SPeter Avalos }
3985382d832SPeter Avalos 
3995382d832SPeter Avalos static DIALOG_CALLBACK *
prev_callback(DIALOG_CALLBACK * p)4005382d832SPeter Avalos prev_callback(DIALOG_CALLBACK * p)
4015382d832SPeter Avalos {
4025382d832SPeter Avalos     DIALOG_CALLBACK *q;
4035382d832SPeter Avalos 
4045382d832SPeter Avalos     if ((p = dialog_state.getc_redirect) != 0) {
4055382d832SPeter Avalos 	if (p == dialog_state.getc_callbacks) {
4065382d832SPeter Avalos 	    for (p = dialog_state.getc_callbacks; p->next != 0; p = p->next) ;
4075382d832SPeter Avalos 	} else {
4085382d832SPeter Avalos 	    for (q = dialog_state.getc_callbacks; q->next != p; q = q->next) ;
4095382d832SPeter Avalos 	    p = q;
4105382d832SPeter Avalos 	}
4115382d832SPeter Avalos     } else {
4125382d832SPeter Avalos 	p = dialog_state.getc_callbacks;
4135382d832SPeter Avalos     }
4145382d832SPeter Avalos     return p;
4155382d832SPeter Avalos }
4165382d832SPeter Avalos 
4175382d832SPeter Avalos #define isBeforeChr(chr) ((chr) == before_chr && !before_fkey)
4185382d832SPeter Avalos #define isBeforeFkey(chr) ((chr) == before_chr && before_fkey)
4195382d832SPeter Avalos 
4205382d832SPeter Avalos /*
4215382d832SPeter Avalos  * Read a character from the given window.  Handle repainting here (to simplify
4225382d832SPeter Avalos  * things in the calling application).  Also, if input-callback(s) are set up,
4235382d832SPeter Avalos  * poll the corresponding files and handle the updates, e.g., for displaying a
4245382d832SPeter Avalos  * tailbox.
4255382d832SPeter Avalos  */
4265382d832SPeter Avalos int
dlg_getc(WINDOW * win,int * fkey)4275382d832SPeter Avalos dlg_getc(WINDOW *win, int *fkey)
4285382d832SPeter Avalos {
4295382d832SPeter Avalos     WINDOW *save_win = win;
4305382d832SPeter Avalos     int ch = ERR;
4315382d832SPeter Avalos     int before_chr;
4325382d832SPeter Avalos     int before_fkey;
4335382d832SPeter Avalos     int result;
4345382d832SPeter Avalos     bool done = FALSE;
4355382d832SPeter Avalos     bool literal = FALSE;
4365382d832SPeter Avalos     DIALOG_CALLBACK *p = 0;
4375940c9abSDaniel Fojt     int interval = dlg_set_timeout(win, may_handle_inputs());
4385382d832SPeter Avalos     time_t expired = time((time_t *) 0) + dialog_vars.timeout_secs;
4395382d832SPeter Avalos     time_t current;
4405382d832SPeter Avalos 
4415382d832SPeter Avalos     while (!done) {
4425382d832SPeter Avalos 	bool handle_others = FALSE;
4435382d832SPeter Avalos 
444*a8e38dc0SAntonio Huete Jimenez 	if (_dlg_find_window(win) == NULL)
445*a8e38dc0SAntonio Huete Jimenez 	    break;
446*a8e38dc0SAntonio Huete Jimenez 
4475382d832SPeter Avalos 	/*
4485382d832SPeter Avalos 	 * If there was no pending file-input, check the keyboard.
4495382d832SPeter Avalos 	 */
4505382d832SPeter Avalos 	ch = really_getch(win, fkey);
4515382d832SPeter Avalos 	if (literal) {
4525382d832SPeter Avalos 	    done = TRUE;
4535382d832SPeter Avalos 	    continue;
4545382d832SPeter Avalos 	}
4555382d832SPeter Avalos 
4565382d832SPeter Avalos 	before_chr = ch;
4575382d832SPeter Avalos 	before_fkey = *fkey;
4585382d832SPeter Avalos 
4595382d832SPeter Avalos 	ch = dlg_lookup_key(win, ch, fkey);
4605382d832SPeter Avalos 	dlg_trace_chr(ch, *fkey);
4615382d832SPeter Avalos 
4625382d832SPeter Avalos 	current = time((time_t *) 0);
4635382d832SPeter Avalos 
4645382d832SPeter Avalos 	/*
4655382d832SPeter Avalos 	 * If we acquired a fkey value, then it is one of dialog's builtin
4665382d832SPeter Avalos 	 * codes such as DLGK_HELPFILE.
4675382d832SPeter Avalos 	 */
4685382d832SPeter Avalos 	if (!*fkey || *fkey != before_fkey) {
4695382d832SPeter Avalos 	    switch (ch) {
4705382d832SPeter Avalos 	    case CHR_LITERAL:
4715382d832SPeter Avalos 		literal = TRUE;
4725382d832SPeter Avalos 		keypad(win, FALSE);
4735382d832SPeter Avalos 		continue;
4745382d832SPeter Avalos 	    case CHR_REPAINT:
475*a8e38dc0SAntonio Huete Jimenez 		if (_dlg_find_window(win)) {
4765382d832SPeter Avalos 		    (void) touchwin(win);
4775382d832SPeter Avalos 		    (void) wrefresh(curscr);
478*a8e38dc0SAntonio Huete Jimenez 		}
4795382d832SPeter Avalos 		break;
4805382d832SPeter Avalos 	    case ERR:		/* wtimeout() in effect; check for file I/O */
4815382d832SPeter Avalos 		if (interval > 0
4825382d832SPeter Avalos 		    && current >= expired) {
483*a8e38dc0SAntonio Huete Jimenez 		    int status;
4845940c9abSDaniel Fojt 		    DLG_TRACE(("# dlg_getc: timeout expired\n"));
485*a8e38dc0SAntonio Huete Jimenez 		    if (dlg_getenv_num("DIALOG_TIMEOUT", &status)) {
486*a8e38dc0SAntonio Huete Jimenez 			dlg_exiterr("timeout");
487*a8e38dc0SAntonio Huete Jimenez 		    }
4885940c9abSDaniel Fojt 		    ch = ESC;
4895940c9abSDaniel Fojt 		    done = TRUE;
4905940c9abSDaniel Fojt 		} else if (!valid_file(stdin)
4915382d832SPeter Avalos 			   || !valid_file(dialog_state.screen_output)) {
4925940c9abSDaniel Fojt 		    DLG_TRACE(("# dlg_getc: input or output is invalid\n"));
4935382d832SPeter Avalos 		    ch = ESC;
4945382d832SPeter Avalos 		    done = TRUE;
4955382d832SPeter Avalos 		} else if (check_inputs()) {
496*a8e38dc0SAntonio Huete Jimenez 		    if (_dlg_find_window(win) && handle_inputs(win))
4975382d832SPeter Avalos 			dlg_raise_window(win);
4985382d832SPeter Avalos 		    else
4995382d832SPeter Avalos 			done = TRUE;
5005382d832SPeter Avalos 		} else {
5015382d832SPeter Avalos 		    done = (interval <= 0);
5025382d832SPeter Avalos 		}
5035382d832SPeter Avalos 		break;
5045382d832SPeter Avalos 	    case DLGK_HELPFILE:
505*a8e38dc0SAntonio Huete Jimenez 		if (dialog_vars.help_file && _dlg_find_window(win)) {
5065382d832SPeter Avalos 		    int yold, xold;
5075382d832SPeter Avalos 		    getyx(win, yold, xold);
5085382d832SPeter Avalos 		    dialog_helpfile("HELP", dialog_vars.help_file, 0, 0);
5095382d832SPeter Avalos 		    dlg_raise_window(win);
5105382d832SPeter Avalos 		    wmove(win, yold, xold);
5115382d832SPeter Avalos 		}
5125382d832SPeter Avalos 		continue;
5135382d832SPeter Avalos 	    case DLGK_FIELD_PREV:
5145382d832SPeter Avalos 		/* FALLTHRU */
5155382d832SPeter Avalos 	    case KEY_BTAB:
5165382d832SPeter Avalos 		/* FALLTHRU */
5175382d832SPeter Avalos 	    case DLGK_FIELD_NEXT:
5185382d832SPeter Avalos 		/* FALLTHRU */
5195382d832SPeter Avalos 	    case TAB:
5205382d832SPeter Avalos 		/* Handle tab/backtab as a special case for traversing between
5215382d832SPeter Avalos 		 * the nominal "current" window, and other windows having
5225382d832SPeter Avalos 		 * callbacks.  If the nominal (control) window closes, we'll
5235382d832SPeter Avalos 		 * close the windows with callbacks.
5245382d832SPeter Avalos 		 */
5255382d832SPeter Avalos 		if (dialog_state.getc_callbacks != 0 &&
5265382d832SPeter Avalos 		    (isBeforeChr(TAB) ||
5275382d832SPeter Avalos 		     isBeforeFkey(KEY_BTAB))) {
5285382d832SPeter Avalos 		    p = (isBeforeChr(TAB)
5295382d832SPeter Avalos 			 ? next_callback(p)
5305382d832SPeter Avalos 			 : prev_callback(p));
5315382d832SPeter Avalos 		    if ((dialog_state.getc_redirect = p) != 0) {
5325382d832SPeter Avalos 			win = p->win;
5335382d832SPeter Avalos 		    } else {
5345382d832SPeter Avalos 			win = save_win;
5355382d832SPeter Avalos 		    }
5365382d832SPeter Avalos 		    dlg_raise_window(win);
5375382d832SPeter Avalos 		    break;
5385382d832SPeter Avalos 		}
5395382d832SPeter Avalos 		/* FALLTHRU */
5405382d832SPeter Avalos 	    default:
5415382d832SPeter Avalos #ifdef NO_LEAKS
5425382d832SPeter Avalos 		if (isBeforeChr(DLG_CTRL('P'))) {
5435382d832SPeter Avalos 		    /* for testing, ^P closes the connection */
5445382d832SPeter Avalos 		    close(0);
5455382d832SPeter Avalos 		    close(1);
5465382d832SPeter Avalos 		    close(2);
5475382d832SPeter Avalos 		    break;
5485382d832SPeter Avalos 		}
5495382d832SPeter Avalos #endif
5505382d832SPeter Avalos 		handle_others = TRUE;
5515382d832SPeter Avalos 		break;
5525382d832SPeter Avalos #ifdef HAVE_DLG_TRACE
5535382d832SPeter Avalos 	    case CHR_TRACE:
5545382d832SPeter Avalos 		dlg_trace_win(win);
5555382d832SPeter Avalos 		break;
5565382d832SPeter Avalos #endif
5575382d832SPeter Avalos 	    }
5585382d832SPeter Avalos 	} else {
5595382d832SPeter Avalos 	    handle_others = TRUE;
5605382d832SPeter Avalos 	}
5615382d832SPeter Avalos 
5625382d832SPeter Avalos 	if (handle_others) {
5635382d832SPeter Avalos 	    if ((p = dialog_state.getc_redirect) != 0) {
5645382d832SPeter Avalos 		if (!(p->handle_getc(p, ch, *fkey, &result))) {
5655382d832SPeter Avalos 		    done = (p->win == save_win) && (!p->keep_win);
5665382d832SPeter Avalos 		    dlg_remove_callback(p);
5675382d832SPeter Avalos 		    dialog_state.getc_redirect = 0;
5685382d832SPeter Avalos 		    win = save_win;
5695382d832SPeter Avalos 		}
5705382d832SPeter Avalos 	    } else {
5715382d832SPeter Avalos 		done = TRUE;
5725382d832SPeter Avalos 	    }
5735382d832SPeter Avalos 	}
5745382d832SPeter Avalos     }
575*a8e38dc0SAntonio Huete Jimenez     if (literal && _dlg_find_window(win))
5765382d832SPeter Avalos 	keypad(win, TRUE);
5775382d832SPeter Avalos     return ch;
5785382d832SPeter Avalos }
5795382d832SPeter Avalos 
5805382d832SPeter Avalos static void
finish_bg(int sig GCC_UNUSED)5815382d832SPeter Avalos finish_bg(int sig GCC_UNUSED)
5825382d832SPeter Avalos {
5835382d832SPeter Avalos     end_dialog();
5845382d832SPeter Avalos     dlg_exit(DLG_EXIT_ERROR);
5855382d832SPeter Avalos }
5865382d832SPeter Avalos 
5875382d832SPeter Avalos /*
5885382d832SPeter Avalos  * If we have callbacks active, purge the list of all that are not marked
5895382d832SPeter Avalos  * to keep in the background.  If any remain, run those in a background
5905382d832SPeter Avalos  * process.
5915382d832SPeter Avalos  */
5925382d832SPeter Avalos void
dlg_killall_bg(int * retval)5935382d832SPeter Avalos dlg_killall_bg(int *retval)
5945382d832SPeter Avalos {
5955382d832SPeter Avalos     DIALOG_CALLBACK *cb;
5965382d832SPeter Avalos #ifdef HAVE_TYPE_UNIONWAIT
5975382d832SPeter Avalos     union wait wstatus;
5985382d832SPeter Avalos #else
5995382d832SPeter Avalos     int wstatus;
6005382d832SPeter Avalos #endif
6015382d832SPeter Avalos 
6025382d832SPeter Avalos     if ((cb = dialog_state.getc_callbacks) != 0) {
6035382d832SPeter Avalos 	while (cb != 0) {
6045382d832SPeter Avalos 	    if (cb->keep_bg) {
6055382d832SPeter Avalos 		cb = cb->next;
6065382d832SPeter Avalos 	    } else {
6075382d832SPeter Avalos 		dlg_remove_callback(cb);
6085382d832SPeter Avalos 		cb = dialog_state.getc_callbacks;
6095382d832SPeter Avalos 	    }
6105382d832SPeter Avalos 	}
6115382d832SPeter Avalos 	if (dialog_state.getc_callbacks != 0) {
6125940c9abSDaniel Fojt 	    int pid;
6135382d832SPeter Avalos 
6145382d832SPeter Avalos 	    refresh();
6155382d832SPeter Avalos 	    fflush(stdout);
6165382d832SPeter Avalos 	    fflush(stderr);
6175382d832SPeter Avalos 	    reset_shell_mode();
6185382d832SPeter Avalos 	    if ((pid = fork()) != 0) {
6195382d832SPeter Avalos 		_exit(pid > 0 ? DLG_EXIT_OK : DLG_EXIT_ERROR);
6205940c9abSDaniel Fojt 	    } else {		/* child, pid==0 */
6215382d832SPeter Avalos 		if ((pid = fork()) != 0) {
6225382d832SPeter Avalos 		    /*
6235382d832SPeter Avalos 		     * Echo the process-id of the grandchild so a shell script
6245382d832SPeter Avalos 		     * can read that, and kill that process.  We'll wait around
6255382d832SPeter Avalos 		     * until then.  Our parent has already left, leaving us
6265382d832SPeter Avalos 		     * temporarily orphaned.
6275382d832SPeter Avalos 		     */
6285382d832SPeter Avalos 		    if (pid > 0) {	/* parent */
6295382d832SPeter Avalos 			fprintf(stderr, "%d\n", pid);
6305382d832SPeter Avalos 			fflush(stderr);
6315382d832SPeter Avalos 		    }
6325382d832SPeter Avalos 		    /* wait for child */
6335382d832SPeter Avalos #ifdef HAVE_WAITPID
6345382d832SPeter Avalos 		    while (-1 == waitpid(pid, &wstatus, 0)) {
6355382d832SPeter Avalos #ifdef EINTR
6365382d832SPeter Avalos 			if (errno == EINTR)
6375382d832SPeter Avalos 			    continue;
6385382d832SPeter Avalos #endif /* EINTR */
6395382d832SPeter Avalos #ifdef ERESTARTSYS
6405382d832SPeter Avalos 			if (errno == ERESTARTSYS)
6415382d832SPeter Avalos 			    continue;
6425382d832SPeter Avalos #endif /* ERESTARTSYS */
6435382d832SPeter Avalos 			break;
6445382d832SPeter Avalos 		    }
6455382d832SPeter Avalos #else
6465382d832SPeter Avalos 		    while (wait(&wstatus) != pid)	/* do nothing */
6475382d832SPeter Avalos 			;
6485382d832SPeter Avalos #endif
6495382d832SPeter Avalos 		    _exit(WEXITSTATUS(wstatus));
6505940c9abSDaniel Fojt 		} else {	/* child, pid==0 */
6515382d832SPeter Avalos 		    if (!dialog_vars.cant_kill)
6525382d832SPeter Avalos 			(void) signal(SIGHUP, finish_bg);
6535382d832SPeter Avalos 		    (void) signal(SIGINT, finish_bg);
6545382d832SPeter Avalos 		    (void) signal(SIGQUIT, finish_bg);
6555382d832SPeter Avalos 		    (void) signal(SIGSEGV, finish_bg);
6565382d832SPeter Avalos 		    while (dialog_state.getc_callbacks != 0) {
6575382d832SPeter Avalos 			int fkey = 0;
6585382d832SPeter Avalos 			dlg_getc_callbacks(ERR, fkey, retval);
6595382d832SPeter Avalos 			napms(1000);
6605382d832SPeter Avalos 		    }
6615382d832SPeter Avalos 		}
6625382d832SPeter Avalos 	    }
6635382d832SPeter Avalos 	}
6645382d832SPeter Avalos     }
6655382d832SPeter Avalos }
666