xref: /freebsd/contrib/dialog/dlg_keys.c (revision a96ef4501919d7ac08e94e98dc34b0bdd744802b)
14c8945a0SNathan Whitehorn /*
2*a96ef450SBaptiste Daroussin  *  $Id: dlg_keys.c,v 1.58 2020/11/26 17:11:56 Glenn.Herteg Exp $
34c8945a0SNathan Whitehorn  *
44c8945a0SNathan Whitehorn  *  dlg_keys.c -- runtime binding support for dialog
54c8945a0SNathan Whitehorn  *
6*a96ef450SBaptiste Daroussin  *  Copyright 2006-2019,2020 Thomas E. Dickey
74c8945a0SNathan Whitehorn  *
84c8945a0SNathan Whitehorn  *  This program is free software; you can redistribute it and/or modify
94c8945a0SNathan Whitehorn  *  it under the terms of the GNU Lesser General Public License, version 2.1
104c8945a0SNathan Whitehorn  *  as published by the Free Software Foundation.
114c8945a0SNathan Whitehorn  *
124c8945a0SNathan Whitehorn  *  This program is distributed in the hope that it will be useful, but
134c8945a0SNathan Whitehorn  *  WITHOUT ANY WARRANTY; without even the implied warranty of
144c8945a0SNathan Whitehorn  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
154c8945a0SNathan Whitehorn  *  Lesser General Public License for more details.
164c8945a0SNathan Whitehorn  *
174c8945a0SNathan Whitehorn  *  You should have received a copy of the GNU Lesser General Public
184c8945a0SNathan Whitehorn  *  License along with this program; if not, write to
194c8945a0SNathan Whitehorn  *	Free Software Foundation, Inc.
204c8945a0SNathan Whitehorn  *	51 Franklin St., Fifth Floor
214c8945a0SNathan Whitehorn  *	Boston, MA 02110, USA.
224c8945a0SNathan Whitehorn  */
234c8945a0SNathan Whitehorn 
244c8945a0SNathan Whitehorn #include <dialog.h>
254c8945a0SNathan Whitehorn #include <dlg_keys.h>
26*a96ef450SBaptiste Daroussin #include <dlg_internals.h>
274c8945a0SNathan Whitehorn 
284c8945a0SNathan Whitehorn #define LIST_BINDINGS struct _list_bindings
294c8945a0SNathan Whitehorn 
30f4f33ea0SBaptiste Daroussin #define CHR_BACKSLASH   '\\'
31f4f33ea0SBaptiste Daroussin #define IsOctal(ch)     ((ch) >= '0' && (ch) <= '7')
32f4f33ea0SBaptiste Daroussin 
334c8945a0SNathan Whitehorn LIST_BINDINGS {
344c8945a0SNathan Whitehorn     LIST_BINDINGS *link;
354c8945a0SNathan Whitehorn     WINDOW *win;		/* window on which widget gets input */
364c8945a0SNathan Whitehorn     const char *name;		/* widget name */
374c8945a0SNathan Whitehorn     bool buttons;		/* true only for dlg_register_buttons() */
384c8945a0SNathan Whitehorn     DLG_KEYS_BINDING *binding;	/* list of bindings */
394c8945a0SNathan Whitehorn };
404c8945a0SNathan Whitehorn 
412a3e3873SBaptiste Daroussin #define WILDNAME "*"
424c8945a0SNathan Whitehorn static LIST_BINDINGS *all_bindings;
434c8945a0SNathan Whitehorn static const DLG_KEYS_BINDING end_keys_binding = END_KEYS_BINDING;
444c8945a0SNathan Whitehorn 
454c8945a0SNathan Whitehorn /*
464c8945a0SNathan Whitehorn  * For a given named widget's window, associate a binding table.
474c8945a0SNathan Whitehorn  */
484c8945a0SNathan Whitehorn void
dlg_register_window(WINDOW * win,const char * name,DLG_KEYS_BINDING * binding)494c8945a0SNathan Whitehorn dlg_register_window(WINDOW *win, const char *name, DLG_KEYS_BINDING * binding)
504c8945a0SNathan Whitehorn {
514c8945a0SNathan Whitehorn     LIST_BINDINGS *p, *q;
524c8945a0SNathan Whitehorn 
534c8945a0SNathan Whitehorn     for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) {
544c8945a0SNathan Whitehorn 	if (p->win == win && !strcmp(p->name, name)) {
554c8945a0SNathan Whitehorn 	    p->binding = binding;
564c8945a0SNathan Whitehorn 	    return;
574c8945a0SNathan Whitehorn 	}
584c8945a0SNathan Whitehorn     }
594c8945a0SNathan Whitehorn     /* add built-in bindings at the end of the list (see compare_bindings). */
604c8945a0SNathan Whitehorn     if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) {
614c8945a0SNathan Whitehorn 	p->win = win;
624c8945a0SNathan Whitehorn 	p->name = name;
634c8945a0SNathan Whitehorn 	p->binding = binding;
64f4f33ea0SBaptiste Daroussin 	if (q != 0) {
654c8945a0SNathan Whitehorn 	    q->link = p;
66f4f33ea0SBaptiste Daroussin 	} else {
674c8945a0SNathan Whitehorn 	    all_bindings = p;
684c8945a0SNathan Whitehorn 	}
69f4f33ea0SBaptiste Daroussin     }
702a3e3873SBaptiste Daroussin #if defined(HAVE_DLG_TRACE) && defined(HAVE_RC_FILE)
712a3e3873SBaptiste Daroussin     /*
722a3e3873SBaptiste Daroussin      * Trace the binding information assigned to this window.  For most widgets
732a3e3873SBaptiste Daroussin      * there is only one binding table.  forms have two, so the trace will be
742a3e3873SBaptiste Daroussin      * longer.  Since compiled-in bindings are only visible when the widget is
752a3e3873SBaptiste Daroussin      * registered, there is no other way to see what bindings are available,
762a3e3873SBaptiste Daroussin      * than by running dialog and tracing it.
772a3e3873SBaptiste Daroussin      */
78f4f33ea0SBaptiste Daroussin     DLG_TRACE(("# dlg_register_window %s\n", name));
79f4f33ea0SBaptiste Daroussin     dlg_dump_keys(dialog_state.trace_output);
802a3e3873SBaptiste Daroussin     dlg_dump_window_keys(dialog_state.trace_output, win);
81f4f33ea0SBaptiste Daroussin     DLG_TRACE(("# ...done dlg_register_window %s\n", name));
822a3e3873SBaptiste Daroussin #endif
834c8945a0SNathan Whitehorn }
844c8945a0SNathan Whitehorn 
854c8945a0SNathan Whitehorn /*
864c8945a0SNathan Whitehorn  * Unlike dlg_lookup_key(), this looks for either widget-builtin or rc-file
874c8945a0SNathan Whitehorn  * definitions, depending on whether 'win' is null.
884c8945a0SNathan Whitehorn  */
894c8945a0SNathan Whitehorn static int
key_is_bound(WINDOW * win,const char * name,int curses_key,int function_key)904c8945a0SNathan Whitehorn key_is_bound(WINDOW *win, const char *name, int curses_key, int function_key)
914c8945a0SNathan Whitehorn {
924c8945a0SNathan Whitehorn     LIST_BINDINGS *p;
934c8945a0SNathan Whitehorn 
944c8945a0SNathan Whitehorn     for (p = all_bindings; p != 0; p = p->link) {
954c8945a0SNathan Whitehorn 	if (p->win == win && !dlg_strcmp(p->name, name)) {
964c8945a0SNathan Whitehorn 	    int n;
974c8945a0SNathan Whitehorn 	    for (n = 0; p->binding[n].is_function_key >= 0; ++n) {
984c8945a0SNathan Whitehorn 		if (p->binding[n].curses_key == curses_key
994c8945a0SNathan Whitehorn 		    && p->binding[n].is_function_key == function_key) {
1004c8945a0SNathan Whitehorn 		    return TRUE;
1014c8945a0SNathan Whitehorn 		}
1024c8945a0SNathan Whitehorn 	    }
1034c8945a0SNathan Whitehorn 	}
1044c8945a0SNathan Whitehorn     }
1054c8945a0SNathan Whitehorn     return FALSE;
1064c8945a0SNathan Whitehorn }
1074c8945a0SNathan Whitehorn 
1084c8945a0SNathan Whitehorn /*
1094c8945a0SNathan Whitehorn  * Call this function after dlg_register_window(), for the list of button
1104c8945a0SNathan Whitehorn  * labels associated with the widget.
1114c8945a0SNathan Whitehorn  *
1124c8945a0SNathan Whitehorn  * Ensure that dlg_lookup_key() will not accidentally translate a key that
1134c8945a0SNathan Whitehorn  * we would like to use for a button abbreviation to some other key, e.g.,
1144c8945a0SNathan Whitehorn  * h/j/k/l for navigation into a cursor key.  Do this by binding the key
1154c8945a0SNathan Whitehorn  * to itself.
1164c8945a0SNathan Whitehorn  *
1174c8945a0SNathan Whitehorn  * See dlg_char_to_button().
1184c8945a0SNathan Whitehorn  */
1194c8945a0SNathan Whitehorn void
dlg_register_buttons(WINDOW * win,const char * name,const char ** buttons)1204c8945a0SNathan Whitehorn dlg_register_buttons(WINDOW *win, const char *name, const char **buttons)
1214c8945a0SNathan Whitehorn {
1224c8945a0SNathan Whitehorn     int n;
1234c8945a0SNathan Whitehorn     LIST_BINDINGS *p;
1244c8945a0SNathan Whitehorn     DLG_KEYS_BINDING *q;
1254c8945a0SNathan Whitehorn 
1264c8945a0SNathan Whitehorn     if (buttons == 0)
1274c8945a0SNathan Whitehorn 	return;
1284c8945a0SNathan Whitehorn 
1294c8945a0SNathan Whitehorn     for (n = 0; buttons[n] != 0; ++n) {
1304c8945a0SNathan Whitehorn 	int curses_key = dlg_button_to_char(buttons[n]);
1314c8945a0SNathan Whitehorn 
132*a96ef450SBaptiste Daroussin 	/* ignore binding if there is no key to bind */
133*a96ef450SBaptiste Daroussin 	if (curses_key < 0)
134*a96ef450SBaptiste Daroussin 	    continue;
135*a96ef450SBaptiste Daroussin 
1364c8945a0SNathan Whitehorn 	/* ignore multibyte characters */
1374c8945a0SNathan Whitehorn 	if (curses_key >= KEY_MIN)
1384c8945a0SNathan Whitehorn 	    continue;
1394c8945a0SNathan Whitehorn 
1404c8945a0SNathan Whitehorn 	/* if it is not bound in the widget, skip it (no conflicts) */
1414c8945a0SNathan Whitehorn 	if (!key_is_bound(win, name, curses_key, FALSE))
1424c8945a0SNathan Whitehorn 	    continue;
1434c8945a0SNathan Whitehorn 
1444c8945a0SNathan Whitehorn #ifdef HAVE_RC_FILE
1454c8945a0SNathan Whitehorn 	/* if it is bound in the rc-file, skip it */
1464c8945a0SNathan Whitehorn 	if (key_is_bound(0, name, curses_key, FALSE))
1474c8945a0SNathan Whitehorn 	    continue;
1484c8945a0SNathan Whitehorn #endif
1494c8945a0SNathan Whitehorn 
1504c8945a0SNathan Whitehorn 	if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) {
1514c8945a0SNathan Whitehorn 	    if ((q = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0) {
1524c8945a0SNathan Whitehorn 		q[0].is_function_key = 0;
1534c8945a0SNathan Whitehorn 		q[0].curses_key = curses_key;
1544c8945a0SNathan Whitehorn 		q[0].dialog_key = curses_key;
1554c8945a0SNathan Whitehorn 		q[1] = end_keys_binding;
1564c8945a0SNathan Whitehorn 
1574c8945a0SNathan Whitehorn 		p->win = win;
1584c8945a0SNathan Whitehorn 		p->name = name;
1594c8945a0SNathan Whitehorn 		p->buttons = TRUE;
1604c8945a0SNathan Whitehorn 		p->binding = q;
1614c8945a0SNathan Whitehorn 
1624c8945a0SNathan Whitehorn 		/* put these at the beginning, to override the widget's table */
1634c8945a0SNathan Whitehorn 		p->link = all_bindings;
1644c8945a0SNathan Whitehorn 		all_bindings = p;
1654c8945a0SNathan Whitehorn 	    } else {
1664c8945a0SNathan Whitehorn 		free(p);
1674c8945a0SNathan Whitehorn 	    }
1684c8945a0SNathan Whitehorn 	}
1694c8945a0SNathan Whitehorn     }
1704c8945a0SNathan Whitehorn }
1714c8945a0SNathan Whitehorn 
1724c8945a0SNathan Whitehorn /*
1734c8945a0SNathan Whitehorn  * Remove the bindings for a given window.
1744c8945a0SNathan Whitehorn  */
1754c8945a0SNathan Whitehorn void
dlg_unregister_window(WINDOW * win)1764c8945a0SNathan Whitehorn dlg_unregister_window(WINDOW *win)
1774c8945a0SNathan Whitehorn {
1784c8945a0SNathan Whitehorn     LIST_BINDINGS *p, *q;
1794c8945a0SNathan Whitehorn 
1804c8945a0SNathan Whitehorn     for (p = all_bindings, q = 0; p != 0; p = p->link) {
1814c8945a0SNathan Whitehorn 	if (p->win == win) {
1824c8945a0SNathan Whitehorn 	    if (q != 0) {
1834c8945a0SNathan Whitehorn 		q->link = p->link;
1844c8945a0SNathan Whitehorn 	    } else {
1854c8945a0SNathan Whitehorn 		all_bindings = p->link;
1864c8945a0SNathan Whitehorn 	    }
1874c8945a0SNathan Whitehorn 	    /* the user-defined and buttons-bindings all are length=1 */
1884c8945a0SNathan Whitehorn 	    if (p->binding[1].is_function_key < 0)
1894c8945a0SNathan Whitehorn 		free(p->binding);
1904c8945a0SNathan Whitehorn 	    free(p);
1914c8945a0SNathan Whitehorn 	    dlg_unregister_window(win);
1924c8945a0SNathan Whitehorn 	    break;
1934c8945a0SNathan Whitehorn 	}
1944c8945a0SNathan Whitehorn 	q = p;
1954c8945a0SNathan Whitehorn     }
1964c8945a0SNathan Whitehorn }
1974c8945a0SNathan Whitehorn 
1984c8945a0SNathan Whitehorn /*
1994c8945a0SNathan Whitehorn  * Call this after wgetch(), using the same window pointer and passing
2004c8945a0SNathan Whitehorn  * the curses-key.
2014c8945a0SNathan Whitehorn  *
2024c8945a0SNathan Whitehorn  * If there is no binding associated with the widget, it simply returns
2034c8945a0SNathan Whitehorn  * the given curses-key.
2044c8945a0SNathan Whitehorn  *
2054c8945a0SNathan Whitehorn  * Parameters:
2064c8945a0SNathan Whitehorn  *	win is the window on which the wgetch() was done.
2074c8945a0SNathan Whitehorn  *	curses_key is the value returned by wgetch().
208f4f33ea0SBaptiste Daroussin  *	fkey in/out (on input, it is nonzero if curses_key is a function key,
209f4f33ea0SBaptiste Daroussin  *		and on output, it is nonzero if the result is a function key).
2104c8945a0SNathan Whitehorn  */
2114c8945a0SNathan Whitehorn int
dlg_lookup_key(WINDOW * win,int curses_key,int * fkey)2124c8945a0SNathan Whitehorn dlg_lookup_key(WINDOW *win, int curses_key, int *fkey)
2134c8945a0SNathan Whitehorn {
2144c8945a0SNathan Whitehorn     LIST_BINDINGS *p;
2152a3e3873SBaptiste Daroussin     DLG_KEYS_BINDING *q;
2164c8945a0SNathan Whitehorn 
2174c8945a0SNathan Whitehorn     /*
2184c8945a0SNathan Whitehorn      * Ignore mouse clicks, since they are already encoded properly.
2194c8945a0SNathan Whitehorn      */
2204c8945a0SNathan Whitehorn #ifdef KEY_MOUSE
2214c8945a0SNathan Whitehorn     if (*fkey != 0 && curses_key == KEY_MOUSE) {
2224c8945a0SNathan Whitehorn 	;
2234c8945a0SNathan Whitehorn     } else
2244c8945a0SNathan Whitehorn #endif
2254c8945a0SNathan Whitehorn 	/*
2264c8945a0SNathan Whitehorn 	 * Ignore resize events, since they are already encoded properly.
2274c8945a0SNathan Whitehorn 	 */
2284c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
2294c8945a0SNathan Whitehorn     if (*fkey != 0 && curses_key == KEY_RESIZE) {
2304c8945a0SNathan Whitehorn 	;
2314c8945a0SNathan Whitehorn     } else
2324c8945a0SNathan Whitehorn #endif
2334c8945a0SNathan Whitehorn     if (*fkey == 0 || curses_key < KEY_MAX) {
2342a3e3873SBaptiste Daroussin 	const char *name = WILDNAME;
2352a3e3873SBaptiste Daroussin 	if (win != 0) {
2364c8945a0SNathan Whitehorn 	    for (p = all_bindings; p != 0; p = p->link) {
2372a3e3873SBaptiste Daroussin 		if (p->win == win) {
2382a3e3873SBaptiste Daroussin 		    name = p->name;
2392a3e3873SBaptiste Daroussin 		    break;
2402a3e3873SBaptiste Daroussin 		}
2412a3e3873SBaptiste Daroussin 	    }
2422a3e3873SBaptiste Daroussin 	}
2432a3e3873SBaptiste Daroussin 	for (p = all_bindings; p != 0; p = p->link) {
244f4f33ea0SBaptiste Daroussin 	    if (p->win == win ||
245f4f33ea0SBaptiste Daroussin 		(p->win == 0 &&
246f4f33ea0SBaptiste Daroussin 		 (!strcmp(p->name, name) || !strcmp(p->name, WILDNAME)))) {
2474c8945a0SNathan Whitehorn 		int function_key = (*fkey != 0);
2482a3e3873SBaptiste Daroussin 		for (q = p->binding; q->is_function_key >= 0; ++q) {
2494c8945a0SNathan Whitehorn 		    if (p->buttons
2504c8945a0SNathan Whitehorn 			&& !function_key
2512a3e3873SBaptiste Daroussin 			&& q->curses_key == (int) dlg_toupper(curses_key)) {
2524c8945a0SNathan Whitehorn 			*fkey = 0;
2532a3e3873SBaptiste Daroussin 			return q->dialog_key;
2544c8945a0SNathan Whitehorn 		    }
2552a3e3873SBaptiste Daroussin 		    if (q->curses_key == curses_key
2562a3e3873SBaptiste Daroussin 			&& q->is_function_key == function_key) {
2572a3e3873SBaptiste Daroussin 			*fkey = q->dialog_key;
2584c8945a0SNathan Whitehorn 			return *fkey;
2594c8945a0SNathan Whitehorn 		    }
2604c8945a0SNathan Whitehorn 		}
2614c8945a0SNathan Whitehorn 	    }
2624c8945a0SNathan Whitehorn 	}
2634c8945a0SNathan Whitehorn     }
2644c8945a0SNathan Whitehorn     return curses_key;
2654c8945a0SNathan Whitehorn }
2664c8945a0SNathan Whitehorn 
2674c8945a0SNathan Whitehorn /*
2684c8945a0SNathan Whitehorn  * Test a dialog internal keycode to see if it corresponds to one of the push
2694c8945a0SNathan Whitehorn  * buttons on the widget such as "OK".
2704c8945a0SNathan Whitehorn  *
2714c8945a0SNathan Whitehorn  * This is only useful if there are user-defined key bindings, since there are
2724c8945a0SNathan Whitehorn  * no built-in bindings that map directly to DLGK_OK, etc.
2734c8945a0SNathan Whitehorn  *
2744c8945a0SNathan Whitehorn  * See also dlg_ok_buttoncode().
2754c8945a0SNathan Whitehorn  */
2764c8945a0SNathan Whitehorn int
dlg_result_key(int dialog_key,int fkey GCC_UNUSED,int * resultp)2774c8945a0SNathan Whitehorn dlg_result_key(int dialog_key, int fkey GCC_UNUSED, int *resultp)
2784c8945a0SNathan Whitehorn {
2794c8945a0SNathan Whitehorn     int done = FALSE;
2804c8945a0SNathan Whitehorn 
281*a96ef450SBaptiste Daroussin     DLG_TRACE(("# dlg_result_key(dialog_key=%d, fkey=%d)\n", dialog_key, fkey));
282*a96ef450SBaptiste Daroussin #ifdef KEY_RESIZE
283*a96ef450SBaptiste Daroussin     if (dialog_state.had_resize) {
284*a96ef450SBaptiste Daroussin 	if (dialog_key == ERR) {
285*a96ef450SBaptiste Daroussin 	    dialog_key = 0;
286*a96ef450SBaptiste Daroussin 	} else {
287*a96ef450SBaptiste Daroussin 	    dialog_state.had_resize = FALSE;
288*a96ef450SBaptiste Daroussin 	}
289*a96ef450SBaptiste Daroussin     } else if (fkey && dialog_key == KEY_RESIZE) {
290*a96ef450SBaptiste Daroussin 	dialog_state.had_resize = TRUE;
291*a96ef450SBaptiste Daroussin     }
292*a96ef450SBaptiste Daroussin #endif
2934c8945a0SNathan Whitehorn #ifdef HAVE_RC_FILE
2944c8945a0SNathan Whitehorn     if (fkey) {
2954c8945a0SNathan Whitehorn 	switch ((DLG_KEYS_ENUM) dialog_key) {
2964c8945a0SNathan Whitehorn 	case DLGK_OK:
297*a96ef450SBaptiste Daroussin 	    if (!dialog_vars.nook) {
2984c8945a0SNathan Whitehorn 		*resultp = DLG_EXIT_OK;
2994c8945a0SNathan Whitehorn 		done = TRUE;
300*a96ef450SBaptiste Daroussin 	    }
3014c8945a0SNathan Whitehorn 	    break;
3024c8945a0SNathan Whitehorn 	case DLGK_CANCEL:
3034c8945a0SNathan Whitehorn 	    if (!dialog_vars.nocancel) {
3044c8945a0SNathan Whitehorn 		*resultp = DLG_EXIT_CANCEL;
3054c8945a0SNathan Whitehorn 		done = TRUE;
3064c8945a0SNathan Whitehorn 	    }
3074c8945a0SNathan Whitehorn 	    break;
3084c8945a0SNathan Whitehorn 	case DLGK_EXTRA:
3094c8945a0SNathan Whitehorn 	    if (dialog_vars.extra_button) {
3104c8945a0SNathan Whitehorn 		*resultp = DLG_EXIT_EXTRA;
3114c8945a0SNathan Whitehorn 		done = TRUE;
3124c8945a0SNathan Whitehorn 	    }
3134c8945a0SNathan Whitehorn 	    break;
3144c8945a0SNathan Whitehorn 	case DLGK_HELP:
3154c8945a0SNathan Whitehorn 	    if (dialog_vars.help_button) {
3164c8945a0SNathan Whitehorn 		*resultp = DLG_EXIT_HELP;
3174c8945a0SNathan Whitehorn 		done = TRUE;
3184c8945a0SNathan Whitehorn 	    }
3194c8945a0SNathan Whitehorn 	    break;
3204c8945a0SNathan Whitehorn 	case DLGK_ESC:
3214c8945a0SNathan Whitehorn 	    *resultp = DLG_EXIT_ESC;
3224c8945a0SNathan Whitehorn 	    done = TRUE;
3234c8945a0SNathan Whitehorn 	    break;
3244c8945a0SNathan Whitehorn 	default:
3254c8945a0SNathan Whitehorn 	    break;
3264c8945a0SNathan Whitehorn 	}
3274c8945a0SNathan Whitehorn     } else
3284c8945a0SNathan Whitehorn #endif
3294c8945a0SNathan Whitehorn     if (dialog_key == ESC) {
3304c8945a0SNathan Whitehorn 	*resultp = DLG_EXIT_ESC;
3314c8945a0SNathan Whitehorn 	done = TRUE;
3324c8945a0SNathan Whitehorn     } else if (dialog_key == ERR) {
3334c8945a0SNathan Whitehorn 	*resultp = DLG_EXIT_ERROR;
3344c8945a0SNathan Whitehorn 	done = TRUE;
3354c8945a0SNathan Whitehorn     }
3364c8945a0SNathan Whitehorn 
3374c8945a0SNathan Whitehorn     return done;
3384c8945a0SNathan Whitehorn }
3394c8945a0SNathan Whitehorn 
340*a96ef450SBaptiste Daroussin /*
341*a96ef450SBaptiste Daroussin  * If a key was bound to one of the button-codes in dlg_result_key(), fake
342*a96ef450SBaptiste Daroussin  * a button-value and an "Enter" key to cause the calling widget to return
343*a96ef450SBaptiste Daroussin  * the corresponding status.
344*a96ef450SBaptiste Daroussin  *
345*a96ef450SBaptiste Daroussin  * See dlg_ok_buttoncode(), which maps settings for ok/extra/help and button
346*a96ef450SBaptiste Daroussin  * number into exit-code.
347*a96ef450SBaptiste Daroussin  */
348*a96ef450SBaptiste Daroussin int
dlg_button_key(int exit_code,int * button,int * dialog_key,int * fkey)349*a96ef450SBaptiste Daroussin dlg_button_key(int exit_code, int *button, int *dialog_key, int *fkey)
350*a96ef450SBaptiste Daroussin {
351*a96ef450SBaptiste Daroussin     int changed = FALSE;
352*a96ef450SBaptiste Daroussin     switch (exit_code) {
353*a96ef450SBaptiste Daroussin     case DLG_EXIT_OK:
354*a96ef450SBaptiste Daroussin 	if (!dialog_vars.nook) {
355*a96ef450SBaptiste Daroussin 	    *button = 0;
356*a96ef450SBaptiste Daroussin 	    changed = TRUE;
357*a96ef450SBaptiste Daroussin 	}
358*a96ef450SBaptiste Daroussin 	break;
359*a96ef450SBaptiste Daroussin     case DLG_EXIT_EXTRA:
360*a96ef450SBaptiste Daroussin 	if (dialog_vars.extra_button) {
361*a96ef450SBaptiste Daroussin 	    *button = dialog_vars.nook ? 0 : 1;
362*a96ef450SBaptiste Daroussin 	    changed = TRUE;
363*a96ef450SBaptiste Daroussin 	}
364*a96ef450SBaptiste Daroussin 	break;
365*a96ef450SBaptiste Daroussin     case DLG_EXIT_CANCEL:
366*a96ef450SBaptiste Daroussin 	if (!dialog_vars.nocancel) {
367*a96ef450SBaptiste Daroussin 	    *button = dialog_vars.nook ? 1 : 2;
368*a96ef450SBaptiste Daroussin 	    changed = TRUE;
369*a96ef450SBaptiste Daroussin 	}
370*a96ef450SBaptiste Daroussin 	break;
371*a96ef450SBaptiste Daroussin     case DLG_EXIT_HELP:
372*a96ef450SBaptiste Daroussin 	if (dialog_vars.help_button) {
373*a96ef450SBaptiste Daroussin 	    int cancel = dialog_vars.nocancel ? 0 : 1;
374*a96ef450SBaptiste Daroussin 	    int extra = dialog_vars.extra_button ? 1 : 0;
375*a96ef450SBaptiste Daroussin 	    int okay = dialog_vars.nook ? 0 : 1;
376*a96ef450SBaptiste Daroussin 	    *button = okay + extra + cancel;
377*a96ef450SBaptiste Daroussin 	    changed = TRUE;
378*a96ef450SBaptiste Daroussin 	}
379*a96ef450SBaptiste Daroussin 	break;
380*a96ef450SBaptiste Daroussin     }
381*a96ef450SBaptiste Daroussin     if (changed) {
382*a96ef450SBaptiste Daroussin 	DLG_TRACE(("# dlg_button_key(%d:%s) button %d\n",
383*a96ef450SBaptiste Daroussin 		   exit_code, dlg_exitcode2s(exit_code), *button));
384*a96ef450SBaptiste Daroussin 	*dialog_key = *fkey = DLGK_ENTER;
385*a96ef450SBaptiste Daroussin     }
386*a96ef450SBaptiste Daroussin     return changed;
387*a96ef450SBaptiste Daroussin }
388*a96ef450SBaptiste Daroussin 
389*a96ef450SBaptiste Daroussin int
dlg_ok_button_key(int exit_code,int * button,int * dialog_key,int * fkey)390*a96ef450SBaptiste Daroussin dlg_ok_button_key(int exit_code, int *button, int *dialog_key, int *fkey)
391*a96ef450SBaptiste Daroussin {
392*a96ef450SBaptiste Daroussin     int result;
393*a96ef450SBaptiste Daroussin     DIALOG_VARS save;
394*a96ef450SBaptiste Daroussin 
395*a96ef450SBaptiste Daroussin     dlg_save_vars(&save);
396*a96ef450SBaptiste Daroussin     dialog_vars.nocancel = TRUE;
397*a96ef450SBaptiste Daroussin 
398*a96ef450SBaptiste Daroussin     result = dlg_button_key(exit_code, button, dialog_key, fkey);
399*a96ef450SBaptiste Daroussin 
400*a96ef450SBaptiste Daroussin     dlg_restore_vars(&save);
401*a96ef450SBaptiste Daroussin     return result;
402*a96ef450SBaptiste Daroussin }
403*a96ef450SBaptiste Daroussin 
4044c8945a0SNathan Whitehorn #ifdef HAVE_RC_FILE
4054c8945a0SNathan Whitehorn typedef struct {
4064c8945a0SNathan Whitehorn     const char *name;
4074c8945a0SNathan Whitehorn     int code;
4084c8945a0SNathan Whitehorn } CODENAME;
4094c8945a0SNathan Whitehorn 
4102a3e3873SBaptiste Daroussin #define ASCII_NAME(name,code)  { #name, code }
4114c8945a0SNathan Whitehorn #define CURSES_NAME(upper) { #upper, KEY_ ## upper }
412f4f33ea0SBaptiste Daroussin #define COUNT_CURSES  TableSize(curses_names)
4134c8945a0SNathan Whitehorn static const CODENAME curses_names[] =
4144c8945a0SNathan Whitehorn {
4152a3e3873SBaptiste Daroussin     ASCII_NAME(ESC, '\033'),
4162a3e3873SBaptiste Daroussin     ASCII_NAME(CR, '\r'),
4172a3e3873SBaptiste Daroussin     ASCII_NAME(LF, '\n'),
4182a3e3873SBaptiste Daroussin     ASCII_NAME(FF, '\f'),
4192a3e3873SBaptiste Daroussin     ASCII_NAME(TAB, '\t'),
4202a3e3873SBaptiste Daroussin     ASCII_NAME(DEL, '\177'),
4212a3e3873SBaptiste Daroussin 
4224c8945a0SNathan Whitehorn     CURSES_NAME(DOWN),
4234c8945a0SNathan Whitehorn     CURSES_NAME(UP),
4244c8945a0SNathan Whitehorn     CURSES_NAME(LEFT),
4254c8945a0SNathan Whitehorn     CURSES_NAME(RIGHT),
4264c8945a0SNathan Whitehorn     CURSES_NAME(HOME),
4274c8945a0SNathan Whitehorn     CURSES_NAME(BACKSPACE),
4284c8945a0SNathan Whitehorn     CURSES_NAME(F0),
4294c8945a0SNathan Whitehorn     CURSES_NAME(DL),
4304c8945a0SNathan Whitehorn     CURSES_NAME(IL),
4314c8945a0SNathan Whitehorn     CURSES_NAME(DC),
4324c8945a0SNathan Whitehorn     CURSES_NAME(IC),
4334c8945a0SNathan Whitehorn     CURSES_NAME(EIC),
4344c8945a0SNathan Whitehorn     CURSES_NAME(CLEAR),
4354c8945a0SNathan Whitehorn     CURSES_NAME(EOS),
4364c8945a0SNathan Whitehorn     CURSES_NAME(EOL),
4374c8945a0SNathan Whitehorn     CURSES_NAME(SF),
4384c8945a0SNathan Whitehorn     CURSES_NAME(SR),
4394c8945a0SNathan Whitehorn     CURSES_NAME(NPAGE),
4404c8945a0SNathan Whitehorn     CURSES_NAME(PPAGE),
4414c8945a0SNathan Whitehorn     CURSES_NAME(STAB),
4424c8945a0SNathan Whitehorn     CURSES_NAME(CTAB),
4434c8945a0SNathan Whitehorn     CURSES_NAME(CATAB),
4444c8945a0SNathan Whitehorn     CURSES_NAME(ENTER),
4454c8945a0SNathan Whitehorn     CURSES_NAME(PRINT),
4464c8945a0SNathan Whitehorn     CURSES_NAME(LL),
4474c8945a0SNathan Whitehorn     CURSES_NAME(A1),
4484c8945a0SNathan Whitehorn     CURSES_NAME(A3),
4494c8945a0SNathan Whitehorn     CURSES_NAME(B2),
4504c8945a0SNathan Whitehorn     CURSES_NAME(C1),
4514c8945a0SNathan Whitehorn     CURSES_NAME(C3),
4524c8945a0SNathan Whitehorn     CURSES_NAME(BTAB),
4534c8945a0SNathan Whitehorn     CURSES_NAME(BEG),
4544c8945a0SNathan Whitehorn     CURSES_NAME(CANCEL),
4554c8945a0SNathan Whitehorn     CURSES_NAME(CLOSE),
4564c8945a0SNathan Whitehorn     CURSES_NAME(COMMAND),
4574c8945a0SNathan Whitehorn     CURSES_NAME(COPY),
4584c8945a0SNathan Whitehorn     CURSES_NAME(CREATE),
4594c8945a0SNathan Whitehorn     CURSES_NAME(END),
4604c8945a0SNathan Whitehorn     CURSES_NAME(EXIT),
4614c8945a0SNathan Whitehorn     CURSES_NAME(FIND),
4624c8945a0SNathan Whitehorn     CURSES_NAME(HELP),
4634c8945a0SNathan Whitehorn     CURSES_NAME(MARK),
4644c8945a0SNathan Whitehorn     CURSES_NAME(MESSAGE),
4654c8945a0SNathan Whitehorn     CURSES_NAME(MOVE),
4664c8945a0SNathan Whitehorn     CURSES_NAME(NEXT),
4674c8945a0SNathan Whitehorn     CURSES_NAME(OPEN),
4684c8945a0SNathan Whitehorn     CURSES_NAME(OPTIONS),
4694c8945a0SNathan Whitehorn     CURSES_NAME(PREVIOUS),
4704c8945a0SNathan Whitehorn     CURSES_NAME(REDO),
4714c8945a0SNathan Whitehorn     CURSES_NAME(REFERENCE),
4724c8945a0SNathan Whitehorn     CURSES_NAME(REFRESH),
4734c8945a0SNathan Whitehorn     CURSES_NAME(REPLACE),
4744c8945a0SNathan Whitehorn     CURSES_NAME(RESTART),
4754c8945a0SNathan Whitehorn     CURSES_NAME(RESUME),
4764c8945a0SNathan Whitehorn     CURSES_NAME(SAVE),
4774c8945a0SNathan Whitehorn     CURSES_NAME(SBEG),
4784c8945a0SNathan Whitehorn     CURSES_NAME(SCANCEL),
4794c8945a0SNathan Whitehorn     CURSES_NAME(SCOMMAND),
4804c8945a0SNathan Whitehorn     CURSES_NAME(SCOPY),
4814c8945a0SNathan Whitehorn     CURSES_NAME(SCREATE),
4824c8945a0SNathan Whitehorn     CURSES_NAME(SDC),
4834c8945a0SNathan Whitehorn     CURSES_NAME(SDL),
4844c8945a0SNathan Whitehorn     CURSES_NAME(SELECT),
4854c8945a0SNathan Whitehorn     CURSES_NAME(SEND),
4864c8945a0SNathan Whitehorn     CURSES_NAME(SEOL),
4874c8945a0SNathan Whitehorn     CURSES_NAME(SEXIT),
4884c8945a0SNathan Whitehorn     CURSES_NAME(SFIND),
4894c8945a0SNathan Whitehorn     CURSES_NAME(SHELP),
4904c8945a0SNathan Whitehorn     CURSES_NAME(SHOME),
4914c8945a0SNathan Whitehorn     CURSES_NAME(SIC),
4924c8945a0SNathan Whitehorn     CURSES_NAME(SLEFT),
4934c8945a0SNathan Whitehorn     CURSES_NAME(SMESSAGE),
4944c8945a0SNathan Whitehorn     CURSES_NAME(SMOVE),
4954c8945a0SNathan Whitehorn     CURSES_NAME(SNEXT),
4964c8945a0SNathan Whitehorn     CURSES_NAME(SOPTIONS),
4974c8945a0SNathan Whitehorn     CURSES_NAME(SPREVIOUS),
4984c8945a0SNathan Whitehorn     CURSES_NAME(SPRINT),
4994c8945a0SNathan Whitehorn     CURSES_NAME(SREDO),
5004c8945a0SNathan Whitehorn     CURSES_NAME(SREPLACE),
5014c8945a0SNathan Whitehorn     CURSES_NAME(SRIGHT),
5024c8945a0SNathan Whitehorn     CURSES_NAME(SRSUME),
5034c8945a0SNathan Whitehorn     CURSES_NAME(SSAVE),
5044c8945a0SNathan Whitehorn     CURSES_NAME(SSUSPEND),
5054c8945a0SNathan Whitehorn     CURSES_NAME(SUNDO),
5064c8945a0SNathan Whitehorn     CURSES_NAME(SUSPEND),
5074c8945a0SNathan Whitehorn     CURSES_NAME(UNDO),
5084c8945a0SNathan Whitehorn };
5094c8945a0SNathan Whitehorn 
5104c8945a0SNathan Whitehorn #define DIALOG_NAME(upper) { #upper, DLGK_ ## upper }
511f4f33ea0SBaptiste Daroussin #define COUNT_DIALOG  TableSize(dialog_names)
5124c8945a0SNathan Whitehorn static const CODENAME dialog_names[] =
5134c8945a0SNathan Whitehorn {
5144c8945a0SNathan Whitehorn     DIALOG_NAME(OK),
5154c8945a0SNathan Whitehorn     DIALOG_NAME(CANCEL),
5164c8945a0SNathan Whitehorn     DIALOG_NAME(EXTRA),
5174c8945a0SNathan Whitehorn     DIALOG_NAME(HELP),
5184c8945a0SNathan Whitehorn     DIALOG_NAME(ESC),
5194c8945a0SNathan Whitehorn     DIALOG_NAME(PAGE_FIRST),
5204c8945a0SNathan Whitehorn     DIALOG_NAME(PAGE_LAST),
5214c8945a0SNathan Whitehorn     DIALOG_NAME(PAGE_NEXT),
5224c8945a0SNathan Whitehorn     DIALOG_NAME(PAGE_PREV),
5234c8945a0SNathan Whitehorn     DIALOG_NAME(ITEM_FIRST),
5244c8945a0SNathan Whitehorn     DIALOG_NAME(ITEM_LAST),
5254c8945a0SNathan Whitehorn     DIALOG_NAME(ITEM_NEXT),
5264c8945a0SNathan Whitehorn     DIALOG_NAME(ITEM_PREV),
5274c8945a0SNathan Whitehorn     DIALOG_NAME(FIELD_FIRST),
5284c8945a0SNathan Whitehorn     DIALOG_NAME(FIELD_LAST),
5294c8945a0SNathan Whitehorn     DIALOG_NAME(FIELD_NEXT),
5304c8945a0SNathan Whitehorn     DIALOG_NAME(FIELD_PREV),
5312a3e3873SBaptiste Daroussin     DIALOG_NAME(FORM_FIRST),
5322a3e3873SBaptiste Daroussin     DIALOG_NAME(FORM_LAST),
5332a3e3873SBaptiste Daroussin     DIALOG_NAME(FORM_NEXT),
5342a3e3873SBaptiste Daroussin     DIALOG_NAME(FORM_PREV),
5354c8945a0SNathan Whitehorn     DIALOG_NAME(GRID_UP),
5364c8945a0SNathan Whitehorn     DIALOG_NAME(GRID_DOWN),
5374c8945a0SNathan Whitehorn     DIALOG_NAME(GRID_LEFT),
5384c8945a0SNathan Whitehorn     DIALOG_NAME(GRID_RIGHT),
5394c8945a0SNathan Whitehorn     DIALOG_NAME(DELETE_LEFT),
5404c8945a0SNathan Whitehorn     DIALOG_NAME(DELETE_RIGHT),
5414c8945a0SNathan Whitehorn     DIALOG_NAME(DELETE_ALL),
5424c8945a0SNathan Whitehorn     DIALOG_NAME(ENTER),
5434c8945a0SNathan Whitehorn     DIALOG_NAME(BEGIN),
5444c8945a0SNathan Whitehorn     DIALOG_NAME(FINAL),
5452a3e3873SBaptiste Daroussin     DIALOG_NAME(SELECT),
5462a3e3873SBaptiste Daroussin     DIALOG_NAME(HELPFILE),
547f4f33ea0SBaptiste Daroussin     DIALOG_NAME(TRACE),
548*a96ef450SBaptiste Daroussin     DIALOG_NAME(TOGGLE),
549*a96ef450SBaptiste Daroussin     DIALOG_NAME(LEAVE)
5504c8945a0SNathan Whitehorn };
5514c8945a0SNathan Whitehorn 
552f4f33ea0SBaptiste Daroussin #define MAP2(letter,actual) { letter, actual }
553f4f33ea0SBaptiste Daroussin 
554f4f33ea0SBaptiste Daroussin static const struct {
555f4f33ea0SBaptiste Daroussin     int letter;
556f4f33ea0SBaptiste Daroussin     int actual;
557f4f33ea0SBaptiste Daroussin } escaped_letters[] = {
558f4f33ea0SBaptiste Daroussin 
559f4f33ea0SBaptiste Daroussin     MAP2('a', DLG_CTRL('G')),
560f4f33ea0SBaptiste Daroussin 	MAP2('b', DLG_CTRL('H')),
561f4f33ea0SBaptiste Daroussin 	MAP2('f', DLG_CTRL('L')),
562f4f33ea0SBaptiste Daroussin 	MAP2('n', DLG_CTRL('J')),
563f4f33ea0SBaptiste Daroussin 	MAP2('r', DLG_CTRL('M')),
564f4f33ea0SBaptiste Daroussin 	MAP2('s', CHR_SPACE),
565f4f33ea0SBaptiste Daroussin 	MAP2('t', DLG_CTRL('I')),
566f4f33ea0SBaptiste Daroussin 	MAP2('\\', '\\'),
567f4f33ea0SBaptiste Daroussin };
568f4f33ea0SBaptiste Daroussin 
569f4f33ea0SBaptiste Daroussin #undef MAP2
570f4f33ea0SBaptiste Daroussin 
5714c8945a0SNathan Whitehorn static char *
skip_white(char * s)5724c8945a0SNathan Whitehorn skip_white(char *s)
5734c8945a0SNathan Whitehorn {
5744c8945a0SNathan Whitehorn     while (*s != '\0' && isspace(UCH(*s)))
5754c8945a0SNathan Whitehorn 	++s;
5764c8945a0SNathan Whitehorn     return s;
5774c8945a0SNathan Whitehorn }
5784c8945a0SNathan Whitehorn 
5794c8945a0SNathan Whitehorn static char *
skip_black(char * s)5804c8945a0SNathan Whitehorn skip_black(char *s)
5814c8945a0SNathan Whitehorn {
5824c8945a0SNathan Whitehorn     while (*s != '\0' && !isspace(UCH(*s)))
5834c8945a0SNathan Whitehorn 	++s;
5844c8945a0SNathan Whitehorn     return s;
5854c8945a0SNathan Whitehorn }
5864c8945a0SNathan Whitehorn 
5874c8945a0SNathan Whitehorn /*
5884c8945a0SNathan Whitehorn  * Find a user-defined binding, given the curses key code.
5894c8945a0SNathan Whitehorn  */
5904c8945a0SNathan Whitehorn static DLG_KEYS_BINDING *
find_binding(char * widget,int curses_key)5914c8945a0SNathan Whitehorn find_binding(char *widget, int curses_key)
5924c8945a0SNathan Whitehorn {
5934c8945a0SNathan Whitehorn     LIST_BINDINGS *p;
5944c8945a0SNathan Whitehorn     DLG_KEYS_BINDING *result = 0;
5954c8945a0SNathan Whitehorn 
5964c8945a0SNathan Whitehorn     for (p = all_bindings; p != 0; p = p->link) {
5974c8945a0SNathan Whitehorn 	if (p->win == 0
5984c8945a0SNathan Whitehorn 	    && !dlg_strcmp(p->name, widget)
5994c8945a0SNathan Whitehorn 	    && p->binding->curses_key == curses_key) {
6004c8945a0SNathan Whitehorn 	    result = p->binding;
6014c8945a0SNathan Whitehorn 	    break;
6024c8945a0SNathan Whitehorn 	}
6034c8945a0SNathan Whitehorn     }
6044c8945a0SNathan Whitehorn     return result;
6054c8945a0SNathan Whitehorn }
6064c8945a0SNathan Whitehorn 
6074c8945a0SNathan Whitehorn /*
6084c8945a0SNathan Whitehorn  * Built-in bindings have a nonzero "win" member, and the associated binding
6094c8945a0SNathan Whitehorn  * table can have more than one entry.  We keep those last, since lookups will
6104c8945a0SNathan Whitehorn  * find the user-defined bindings first and use those.
6114c8945a0SNathan Whitehorn  *
6124c8945a0SNathan Whitehorn  * Sort "*" (all-widgets) entries past named widgets, since those are less
6134c8945a0SNathan Whitehorn  * specific.
6144c8945a0SNathan Whitehorn  */
6154c8945a0SNathan Whitehorn static int
compare_bindings(LIST_BINDINGS * a,LIST_BINDINGS * b)6164c8945a0SNathan Whitehorn compare_bindings(LIST_BINDINGS * a, LIST_BINDINGS * b)
6174c8945a0SNathan Whitehorn {
6184c8945a0SNathan Whitehorn     int result = 0;
6194c8945a0SNathan Whitehorn     if (a->win == b->win) {
6204c8945a0SNathan Whitehorn 	if (!strcmp(a->name, b->name)) {
6214c8945a0SNathan Whitehorn 	    result = a->binding[0].curses_key - b->binding[0].curses_key;
6222a3e3873SBaptiste Daroussin 	} else if (!strcmp(b->name, WILDNAME)) {
6234c8945a0SNathan Whitehorn 	    result = -1;
6242a3e3873SBaptiste Daroussin 	} else if (!strcmp(a->name, WILDNAME)) {
6254c8945a0SNathan Whitehorn 	    result = 1;
6264c8945a0SNathan Whitehorn 	} else {
6274c8945a0SNathan Whitehorn 	    result = dlg_strcmp(a->name, b->name);
6284c8945a0SNathan Whitehorn 	}
6294c8945a0SNathan Whitehorn     } else if (b->win) {
6304c8945a0SNathan Whitehorn 	result = -1;
6314c8945a0SNathan Whitehorn     } else {
6324c8945a0SNathan Whitehorn 	result = 1;
6334c8945a0SNathan Whitehorn     }
6344c8945a0SNathan Whitehorn     return result;
6354c8945a0SNathan Whitehorn }
6364c8945a0SNathan Whitehorn 
6374c8945a0SNathan Whitehorn /*
6384c8945a0SNathan Whitehorn  * Find a user-defined binding, given the curses key code.  If it does not
6394c8945a0SNathan Whitehorn  * exist, create a new one, inserting it into the linked list, keeping it
6404c8945a0SNathan Whitehorn  * sorted to simplify lookups for user-defined bindings that can override
6414c8945a0SNathan Whitehorn  * the built-in bindings.
6424c8945a0SNathan Whitehorn  */
6434c8945a0SNathan Whitehorn static DLG_KEYS_BINDING *
make_binding(char * widget,int curses_key,int is_function,int dialog_key)6444c8945a0SNathan Whitehorn make_binding(char *widget, int curses_key, int is_function, int dialog_key)
6454c8945a0SNathan Whitehorn {
6464c8945a0SNathan Whitehorn     LIST_BINDINGS *entry = 0;
6474c8945a0SNathan Whitehorn     DLG_KEYS_BINDING *data = 0;
6484c8945a0SNathan Whitehorn     char *name;
6494c8945a0SNathan Whitehorn     DLG_KEYS_BINDING *result = find_binding(widget, curses_key);
6504c8945a0SNathan Whitehorn 
6514c8945a0SNathan Whitehorn     if (result == 0
6524c8945a0SNathan Whitehorn 	&& (entry = dlg_calloc(LIST_BINDINGS, 1)) != 0
6534c8945a0SNathan Whitehorn 	&& (data = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0
6544c8945a0SNathan Whitehorn 	&& (name = dlg_strclone(widget)) != 0) {
655*a96ef450SBaptiste Daroussin 	LIST_BINDINGS *p, *q;
6564c8945a0SNathan Whitehorn 
6574c8945a0SNathan Whitehorn 	entry->name = name;
6584c8945a0SNathan Whitehorn 	entry->binding = data;
6594c8945a0SNathan Whitehorn 
6604c8945a0SNathan Whitehorn 	data[0].is_function_key = is_function;
6614c8945a0SNathan Whitehorn 	data[0].curses_key = curses_key;
6624c8945a0SNathan Whitehorn 	data[0].dialog_key = dialog_key;
6634c8945a0SNathan Whitehorn 
6644c8945a0SNathan Whitehorn 	data[1] = end_keys_binding;
6654c8945a0SNathan Whitehorn 
6664c8945a0SNathan Whitehorn 	for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) {
6674c8945a0SNathan Whitehorn 	    if (compare_bindings(entry, p) < 0) {
6684c8945a0SNathan Whitehorn 		break;
6694c8945a0SNathan Whitehorn 	    }
6704c8945a0SNathan Whitehorn 	}
6714c8945a0SNathan Whitehorn 	if (q != 0) {
6724c8945a0SNathan Whitehorn 	    q->link = entry;
6734c8945a0SNathan Whitehorn 	} else {
6744c8945a0SNathan Whitehorn 	    all_bindings = entry;
6754c8945a0SNathan Whitehorn 	}
6764c8945a0SNathan Whitehorn 	if (p != 0) {
6774c8945a0SNathan Whitehorn 	    entry->link = p;
6784c8945a0SNathan Whitehorn 	}
6794c8945a0SNathan Whitehorn 	result = data;
6804c8945a0SNathan Whitehorn     } else if (entry != 0) {
6814c8945a0SNathan Whitehorn 	free(entry);
6824c8945a0SNathan Whitehorn 	if (data)
6834c8945a0SNathan Whitehorn 	    free(data);
6844c8945a0SNathan Whitehorn     }
6854c8945a0SNathan Whitehorn 
6864c8945a0SNathan Whitehorn     return result;
6874c8945a0SNathan Whitehorn }
6884c8945a0SNathan Whitehorn 
689f4f33ea0SBaptiste Daroussin static int
decode_escaped(char ** string)690f4f33ea0SBaptiste Daroussin decode_escaped(char **string)
691f4f33ea0SBaptiste Daroussin {
692f4f33ea0SBaptiste Daroussin     int result = 0;
693f4f33ea0SBaptiste Daroussin 
694f4f33ea0SBaptiste Daroussin     if (IsOctal(**string)) {
695f4f33ea0SBaptiste Daroussin 	int limit = 3;
696f4f33ea0SBaptiste Daroussin 	while (limit-- > 0 && IsOctal(**string)) {
697f4f33ea0SBaptiste Daroussin 	    int ch = (**string);
698f4f33ea0SBaptiste Daroussin 	    *string += 1;
699f4f33ea0SBaptiste Daroussin 	    result = (result << 3) | (ch - '0');
700f4f33ea0SBaptiste Daroussin 	}
701f4f33ea0SBaptiste Daroussin     } else {
702*a96ef450SBaptiste Daroussin 	unsigned n;
703*a96ef450SBaptiste Daroussin 
704f4f33ea0SBaptiste Daroussin 	for (n = 0; n < TableSize(escaped_letters); ++n) {
705f4f33ea0SBaptiste Daroussin 	    if (**string == escaped_letters[n].letter) {
706f4f33ea0SBaptiste Daroussin 		*string += 1;
707f4f33ea0SBaptiste Daroussin 		result = escaped_letters[n].actual;
708f4f33ea0SBaptiste Daroussin 		break;
709f4f33ea0SBaptiste Daroussin 	    }
710f4f33ea0SBaptiste Daroussin 	}
711f4f33ea0SBaptiste Daroussin     }
712f4f33ea0SBaptiste Daroussin     return result;
713f4f33ea0SBaptiste Daroussin }
714f4f33ea0SBaptiste Daroussin 
715f4f33ea0SBaptiste Daroussin static char *
encode_escaped(int value)716f4f33ea0SBaptiste Daroussin encode_escaped(int value)
717f4f33ea0SBaptiste Daroussin {
718f4f33ea0SBaptiste Daroussin     static char result[80];
719f4f33ea0SBaptiste Daroussin     unsigned n;
720f4f33ea0SBaptiste Daroussin     bool found = FALSE;
721f4f33ea0SBaptiste Daroussin     for (n = 0; n < TableSize(escaped_letters); ++n) {
722f4f33ea0SBaptiste Daroussin 	if (value == escaped_letters[n].actual) {
723f4f33ea0SBaptiste Daroussin 	    found = TRUE;
724f4f33ea0SBaptiste Daroussin 	    sprintf(result, "%c", escaped_letters[n].letter);
725f4f33ea0SBaptiste Daroussin 	    break;
726f4f33ea0SBaptiste Daroussin 	}
727f4f33ea0SBaptiste Daroussin     }
728f4f33ea0SBaptiste Daroussin     if (!found) {
729f4f33ea0SBaptiste Daroussin 	sprintf(result, "%03o", value & 0xff);
730f4f33ea0SBaptiste Daroussin     }
731f4f33ea0SBaptiste Daroussin     return result;
732f4f33ea0SBaptiste Daroussin }
733f4f33ea0SBaptiste Daroussin 
7344c8945a0SNathan Whitehorn /*
735f4f33ea0SBaptiste Daroussin  * Parse the parameters of the "bindkey" configuration-file entry.  This
7364c8945a0SNathan Whitehorn  * expects widget name which may be "*", followed by curses key definition and
7374c8945a0SNathan Whitehorn  * then dialog key definition.
7384c8945a0SNathan Whitehorn  *
7394c8945a0SNathan Whitehorn  * The curses key "should" be one of the names (ignoring case) from
7404c8945a0SNathan Whitehorn  * curses_names[], but may also be a single control character (prefix "^" or
7414c8945a0SNathan Whitehorn  * "~" depending on whether it is C0 or C1), or an escaped single character.
7424c8945a0SNathan Whitehorn  * Binding a printable character with dialog is possible but not useful.
7434c8945a0SNathan Whitehorn  *
7444c8945a0SNathan Whitehorn  * The dialog key must be one of the names from dialog_names[].
7454c8945a0SNathan Whitehorn  */
7464c8945a0SNathan Whitehorn int
dlg_parse_bindkey(char * params)7474c8945a0SNathan Whitehorn dlg_parse_bindkey(char *params)
7484c8945a0SNathan Whitehorn {
7494c8945a0SNathan Whitehorn     char *p = skip_white(params);
7504c8945a0SNathan Whitehorn     int result = FALSE;
7514c8945a0SNathan Whitehorn     char *widget;
7524c8945a0SNathan Whitehorn     int curses_key;
7534c8945a0SNathan Whitehorn     int dialog_key;
7544c8945a0SNathan Whitehorn 
7554c8945a0SNathan Whitehorn     curses_key = -1;
7564c8945a0SNathan Whitehorn     dialog_key = -1;
7574c8945a0SNathan Whitehorn     widget = p;
7584c8945a0SNathan Whitehorn 
7594c8945a0SNathan Whitehorn     p = skip_black(p);
7604c8945a0SNathan Whitehorn     if (p != widget && *p != '\0') {
761*a96ef450SBaptiste Daroussin 	char *q;
762*a96ef450SBaptiste Daroussin 	unsigned xx;
763*a96ef450SBaptiste Daroussin 	bool escaped = FALSE;
764*a96ef450SBaptiste Daroussin 	int modified = 0;
765*a96ef450SBaptiste Daroussin 	int is_function = FALSE;
766*a96ef450SBaptiste Daroussin 
7674c8945a0SNathan Whitehorn 	*p++ = '\0';
7682a3e3873SBaptiste Daroussin 	p = skip_white(p);
7694c8945a0SNathan Whitehorn 	q = p;
7704c8945a0SNathan Whitehorn 	while (*p != '\0' && curses_key < 0) {
7714c8945a0SNathan Whitehorn 	    if (escaped) {
7724c8945a0SNathan Whitehorn 		escaped = FALSE;
773f4f33ea0SBaptiste Daroussin 		curses_key = decode_escaped(&p);
774f4f33ea0SBaptiste Daroussin 	    } else if (*p == CHR_BACKSLASH) {
7754c8945a0SNathan Whitehorn 		escaped = TRUE;
7764c8945a0SNathan Whitehorn 	    } else if (modified) {
7774c8945a0SNathan Whitehorn 		if (*p == '?') {
7784c8945a0SNathan Whitehorn 		    curses_key = ((modified == '^')
7794c8945a0SNathan Whitehorn 				  ? 127
7804c8945a0SNathan Whitehorn 				  : 255);
7814c8945a0SNathan Whitehorn 		} else {
7824c8945a0SNathan Whitehorn 		    curses_key = ((modified == '^')
7834c8945a0SNathan Whitehorn 				  ? (*p & 0x1f)
7844c8945a0SNathan Whitehorn 				  : ((*p & 0x1f) | 0x80));
7854c8945a0SNathan Whitehorn 		}
7864c8945a0SNathan Whitehorn 	    } else if (*p == '^') {
7874c8945a0SNathan Whitehorn 		modified = *p;
7884c8945a0SNathan Whitehorn 	    } else if (*p == '~') {
7894c8945a0SNathan Whitehorn 		modified = *p;
7904c8945a0SNathan Whitehorn 	    } else if (isspace(UCH(*p))) {
7914c8945a0SNathan Whitehorn 		break;
7924c8945a0SNathan Whitehorn 	    }
7934c8945a0SNathan Whitehorn 	    ++p;
7944c8945a0SNathan Whitehorn 	}
7954c8945a0SNathan Whitehorn 	if (!isspace(UCH(*p))) {
7964c8945a0SNathan Whitehorn 	    ;
7974c8945a0SNathan Whitehorn 	} else {
7984c8945a0SNathan Whitehorn 	    *p++ = '\0';
7994c8945a0SNathan Whitehorn 	    if (curses_key < 0) {
8004c8945a0SNathan Whitehorn 		char fprefix[2];
8014c8945a0SNathan Whitehorn 		char check[2];
8024c8945a0SNathan Whitehorn 		int keynumber;
803*a96ef450SBaptiste Daroussin 		if (sscanf(q, "%1[Ff]%d%c", fprefix, &keynumber, check) == 2) {
8044c8945a0SNathan Whitehorn 		    curses_key = KEY_F(keynumber);
8054c8945a0SNathan Whitehorn 		    is_function = TRUE;
8064c8945a0SNathan Whitehorn 		} else {
8074c8945a0SNathan Whitehorn 		    for (xx = 0; xx < COUNT_CURSES; ++xx) {
8084c8945a0SNathan Whitehorn 			if (!dlg_strcmp(curses_names[xx].name, q)) {
8094c8945a0SNathan Whitehorn 			    curses_key = curses_names[xx].code;
8102a3e3873SBaptiste Daroussin 			    is_function = (curses_key >= KEY_MIN);
8114c8945a0SNathan Whitehorn 			    break;
8124c8945a0SNathan Whitehorn 			}
8134c8945a0SNathan Whitehorn 		    }
8144c8945a0SNathan Whitehorn 		}
8154c8945a0SNathan Whitehorn 	    }
8164c8945a0SNathan Whitehorn 	}
8174c8945a0SNathan Whitehorn 	q = skip_white(p);
8184c8945a0SNathan Whitehorn 	p = skip_black(q);
8194c8945a0SNathan Whitehorn 	if (p != q) {
8204c8945a0SNathan Whitehorn 	    for (xx = 0; xx < COUNT_DIALOG; ++xx) {
8214c8945a0SNathan Whitehorn 		if (!dlg_strcmp(dialog_names[xx].name, q)) {
8224c8945a0SNathan Whitehorn 		    dialog_key = dialog_names[xx].code;
8234c8945a0SNathan Whitehorn 		    break;
8244c8945a0SNathan Whitehorn 		}
8254c8945a0SNathan Whitehorn 	    }
8264c8945a0SNathan Whitehorn 	}
8274c8945a0SNathan Whitehorn 	if (*widget != '\0'
8284c8945a0SNathan Whitehorn 	    && curses_key >= 0
8294c8945a0SNathan Whitehorn 	    && dialog_key >= 0
8304c8945a0SNathan Whitehorn 	    && make_binding(widget, curses_key, is_function, dialog_key) != 0) {
8314c8945a0SNathan Whitehorn 	    result = TRUE;
8324c8945a0SNathan Whitehorn 	}
8334c8945a0SNathan Whitehorn     }
8344c8945a0SNathan Whitehorn     return result;
8354c8945a0SNathan Whitehorn }
8364c8945a0SNathan Whitehorn 
8374c8945a0SNathan Whitehorn static void
dump_curses_key(FILE * fp,int curses_key)8384c8945a0SNathan Whitehorn dump_curses_key(FILE *fp, int curses_key)
8394c8945a0SNathan Whitehorn {
8404c8945a0SNathan Whitehorn     if (curses_key > KEY_MIN) {
8414c8945a0SNathan Whitehorn 	unsigned n;
8424c8945a0SNathan Whitehorn 	bool found = FALSE;
8434c8945a0SNathan Whitehorn 	for (n = 0; n < COUNT_CURSES; ++n) {
8444c8945a0SNathan Whitehorn 	    if (curses_names[n].code == curses_key) {
8454c8945a0SNathan Whitehorn 		fprintf(fp, "%s", curses_names[n].name);
8464c8945a0SNathan Whitehorn 		found = TRUE;
8474c8945a0SNathan Whitehorn 		break;
8484c8945a0SNathan Whitehorn 	    }
8494c8945a0SNathan Whitehorn 	}
8504c8945a0SNathan Whitehorn 	if (!found) {
851f4f33ea0SBaptiste Daroussin #ifdef KEY_MOUSE
852f4f33ea0SBaptiste Daroussin 	    if (is_DLGK_MOUSE(curses_key)) {
853f4f33ea0SBaptiste Daroussin 		fprintf(fp, "MOUSE-");
854f4f33ea0SBaptiste Daroussin 		dump_curses_key(fp, curses_key - M_EVENT);
855f4f33ea0SBaptiste Daroussin 	    } else
856f4f33ea0SBaptiste Daroussin #endif
8574c8945a0SNathan Whitehorn 	    if (curses_key >= KEY_F(0)) {
8584c8945a0SNathan Whitehorn 		fprintf(fp, "F%d", curses_key - KEY_F(0));
8594c8945a0SNathan Whitehorn 	    } else {
8604c8945a0SNathan Whitehorn 		fprintf(fp, "curses%d", curses_key);
8614c8945a0SNathan Whitehorn 	    }
8624c8945a0SNathan Whitehorn 	}
8634c8945a0SNathan Whitehorn     } else if (curses_key >= 0 && curses_key < 32) {
8644c8945a0SNathan Whitehorn 	fprintf(fp, "^%c", curses_key + 64);
8654c8945a0SNathan Whitehorn     } else if (curses_key == 127) {
8664c8945a0SNathan Whitehorn 	fprintf(fp, "^?");
8674c8945a0SNathan Whitehorn     } else if (curses_key >= 128 && curses_key < 160) {
8684c8945a0SNathan Whitehorn 	fprintf(fp, "~%c", curses_key - 64);
8694c8945a0SNathan Whitehorn     } else if (curses_key == 255) {
8704c8945a0SNathan Whitehorn 	fprintf(fp, "~?");
871f4f33ea0SBaptiste Daroussin     } else if (curses_key > 32 &&
872f4f33ea0SBaptiste Daroussin 	       curses_key < 127 &&
873f4f33ea0SBaptiste Daroussin 	       curses_key != CHR_BACKSLASH) {
874f4f33ea0SBaptiste Daroussin 	fprintf(fp, "%c", curses_key);
8754c8945a0SNathan Whitehorn     } else {
876f4f33ea0SBaptiste Daroussin 	fprintf(fp, "%c%s", CHR_BACKSLASH, encode_escaped(curses_key));
8774c8945a0SNathan Whitehorn     }
8784c8945a0SNathan Whitehorn }
8794c8945a0SNathan Whitehorn 
8804c8945a0SNathan Whitehorn static void
dump_dialog_key(FILE * fp,int dialog_key)8814c8945a0SNathan Whitehorn dump_dialog_key(FILE *fp, int dialog_key)
8824c8945a0SNathan Whitehorn {
8834c8945a0SNathan Whitehorn     unsigned n;
8844c8945a0SNathan Whitehorn     bool found = FALSE;
8854c8945a0SNathan Whitehorn     for (n = 0; n < COUNT_DIALOG; ++n) {
8864c8945a0SNathan Whitehorn 	if (dialog_names[n].code == dialog_key) {
8874c8945a0SNathan Whitehorn 	    fputs(dialog_names[n].name, fp);
8884c8945a0SNathan Whitehorn 	    found = TRUE;
8894c8945a0SNathan Whitehorn 	    break;
8904c8945a0SNathan Whitehorn 	}
8914c8945a0SNathan Whitehorn     }
8924c8945a0SNathan Whitehorn     if (!found) {
8934c8945a0SNathan Whitehorn 	fprintf(fp, "dialog%d", dialog_key);
8944c8945a0SNathan Whitehorn     }
8954c8945a0SNathan Whitehorn }
8964c8945a0SNathan Whitehorn 
8974c8945a0SNathan Whitehorn static void
dump_one_binding(FILE * fp,WINDOW * win,const char * widget,DLG_KEYS_BINDING * binding)898f4f33ea0SBaptiste Daroussin dump_one_binding(FILE *fp,
899f4f33ea0SBaptiste Daroussin 		 WINDOW *win,
900f4f33ea0SBaptiste Daroussin 		 const char *widget,
901f4f33ea0SBaptiste Daroussin 		 DLG_KEYS_BINDING * binding)
9024c8945a0SNathan Whitehorn {
903f4f33ea0SBaptiste Daroussin     int actual;
904f4f33ea0SBaptiste Daroussin     int fkey = (binding->curses_key > 255);
905f4f33ea0SBaptiste Daroussin 
9064c8945a0SNathan Whitehorn     fprintf(fp, "bindkey %s ", widget);
9074c8945a0SNathan Whitehorn     dump_curses_key(fp, binding->curses_key);
9084c8945a0SNathan Whitehorn     fputc(' ', fp);
9094c8945a0SNathan Whitehorn     dump_dialog_key(fp, binding->dialog_key);
910f4f33ea0SBaptiste Daroussin     actual = dlg_lookup_key(win, binding->curses_key, &fkey);
911f4f33ea0SBaptiste Daroussin #ifdef KEY_MOUSE
912f4f33ea0SBaptiste Daroussin     if (is_DLGK_MOUSE(binding->curses_key) && is_DLGK_MOUSE(actual)) {
913f4f33ea0SBaptiste Daroussin 	;			/* EMPTY */
914f4f33ea0SBaptiste Daroussin     } else
915f4f33ea0SBaptiste Daroussin #endif
916f4f33ea0SBaptiste Daroussin     if (actual != binding->dialog_key) {
917f4f33ea0SBaptiste Daroussin 	fprintf(fp, "\t# overridden by ");
918f4f33ea0SBaptiste Daroussin 	dump_dialog_key(fp, actual);
919f4f33ea0SBaptiste Daroussin     }
9204c8945a0SNathan Whitehorn     fputc('\n', fp);
9214c8945a0SNathan Whitehorn }
9224c8945a0SNathan Whitehorn 
9232a3e3873SBaptiste Daroussin /*
9242a3e3873SBaptiste Daroussin  * Dump bindings for the given window.  If it is a null, then this dumps the
9252a3e3873SBaptiste Daroussin  * initial bindings which were loaded from the rc-file that are used as
9262a3e3873SBaptiste Daroussin  * overall defaults.
9272a3e3873SBaptiste Daroussin  */
9282a3e3873SBaptiste Daroussin void
dlg_dump_window_keys(FILE * fp,WINDOW * win)9292a3e3873SBaptiste Daroussin dlg_dump_window_keys(FILE *fp, WINDOW *win)
9302a3e3873SBaptiste Daroussin {
9312a3e3873SBaptiste Daroussin     if (fp != 0) {
9322a3e3873SBaptiste Daroussin 	LIST_BINDINGS *p;
9332a3e3873SBaptiste Daroussin 	DLG_KEYS_BINDING *q;
9342a3e3873SBaptiste Daroussin 	const char *last = "";
9352a3e3873SBaptiste Daroussin 
9362a3e3873SBaptiste Daroussin 	for (p = all_bindings; p != 0; p = p->link) {
9372a3e3873SBaptiste Daroussin 	    if (p->win == win) {
9382a3e3873SBaptiste Daroussin 		if (dlg_strcmp(last, p->name)) {
939f4f33ea0SBaptiste Daroussin 		    fprintf(fp, "# key bindings for %s widgets%s\n",
940f4f33ea0SBaptiste Daroussin 			    !strcmp(p->name, WILDNAME) ? "all" : p->name,
941f4f33ea0SBaptiste Daroussin 			    win == 0 ? " (user-defined)" : "");
9422a3e3873SBaptiste Daroussin 		    last = p->name;
9432a3e3873SBaptiste Daroussin 		}
9442a3e3873SBaptiste Daroussin 		for (q = p->binding; q->is_function_key >= 0; ++q) {
945f4f33ea0SBaptiste Daroussin 		    dump_one_binding(fp, win, p->name, q);
9462a3e3873SBaptiste Daroussin 		}
9472a3e3873SBaptiste Daroussin 	    }
9482a3e3873SBaptiste Daroussin 	}
9492a3e3873SBaptiste Daroussin     }
9502a3e3873SBaptiste Daroussin }
9512a3e3873SBaptiste Daroussin 
9522a3e3873SBaptiste Daroussin /*
9532a3e3873SBaptiste Daroussin  * Dump all of the bindings which are not specific to a given widget, i.e.,
9542a3e3873SBaptiste Daroussin  * the "win" member is null.
9552a3e3873SBaptiste Daroussin  */
9564c8945a0SNathan Whitehorn void
dlg_dump_keys(FILE * fp)9574c8945a0SNathan Whitehorn dlg_dump_keys(FILE *fp)
9584c8945a0SNathan Whitehorn {
9592a3e3873SBaptiste Daroussin     if (fp != 0) {
9604c8945a0SNathan Whitehorn 	LIST_BINDINGS *p;
9614c8945a0SNathan Whitehorn 	unsigned count = 0;
9624c8945a0SNathan Whitehorn 
9634c8945a0SNathan Whitehorn 	for (p = all_bindings; p != 0; p = p->link) {
9644c8945a0SNathan Whitehorn 	    if (p->win == 0) {
9654c8945a0SNathan Whitehorn 		++count;
9664c8945a0SNathan Whitehorn 	    }
9674c8945a0SNathan Whitehorn 	}
9684c8945a0SNathan Whitehorn 	if (count != 0) {
9692a3e3873SBaptiste Daroussin 	    dlg_dump_window_keys(fp, 0);
9704c8945a0SNathan Whitehorn 	}
9714c8945a0SNathan Whitehorn     }
9724c8945a0SNathan Whitehorn }
9734c8945a0SNathan Whitehorn #endif /* HAVE_RC_FILE */
974