xref: /freebsd/contrib/dialog/fselect.c (revision a96ef4501919d7ac08e94e98dc34b0bdd744802b)
14c8945a0SNathan Whitehorn /*
2*a96ef450SBaptiste Daroussin  *  $Id: fselect.c,v 1.115 2021/01/16 17:19:15 tom Exp $
34c8945a0SNathan Whitehorn  *
44c8945a0SNathan Whitehorn  *  fselect.c -- implements the file-selector box
54c8945a0SNathan Whitehorn  *
6*a96ef450SBaptiste Daroussin  *  Copyright 2000-2020,2021	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 
24*a96ef450SBaptiste Daroussin #include <dlg_internals.h>
254c8945a0SNathan Whitehorn #include <dlg_keys.h>
264c8945a0SNathan Whitehorn 
274c8945a0SNathan Whitehorn #include <sys/types.h>
284c8945a0SNathan Whitehorn #include <sys/stat.h>
294c8945a0SNathan Whitehorn 
304c8945a0SNathan Whitehorn #if HAVE_DIRENT_H
314c8945a0SNathan Whitehorn # include <dirent.h>
324c8945a0SNathan Whitehorn # define NAMLEN(dirent) strlen((dirent)->d_name)
334c8945a0SNathan Whitehorn #else
344c8945a0SNathan Whitehorn # define dirent direct
354c8945a0SNathan Whitehorn # define NAMLEN(dirent) (dirent)->d_namlen
364c8945a0SNathan Whitehorn # if HAVE_SYS_NDIR_H
374c8945a0SNathan Whitehorn #  include <sys/ndir.h>
384c8945a0SNathan Whitehorn # endif
394c8945a0SNathan Whitehorn # if HAVE_SYS_DIR_H
404c8945a0SNathan Whitehorn #  include <sys/dir.h>
414c8945a0SNathan Whitehorn # endif
424c8945a0SNathan Whitehorn # if HAVE_NDIR_H
434c8945a0SNathan Whitehorn #  include <ndir.h>
444c8945a0SNathan Whitehorn # endif
454c8945a0SNathan Whitehorn #endif
464c8945a0SNathan Whitehorn 
474c8945a0SNathan Whitehorn # if defined(_FILE_OFFSET_BITS) && defined(HAVE_STRUCT_DIRENT64)
484c8945a0SNathan Whitehorn #  if !defined(_LP64) && (_FILE_OFFSET_BITS == 64)
494c8945a0SNathan Whitehorn #   define      DIRENT  struct dirent64
504c8945a0SNathan Whitehorn #  else
514c8945a0SNathan Whitehorn #   define      DIRENT  struct dirent
524c8945a0SNathan Whitehorn #  endif
534c8945a0SNathan Whitehorn # else
544c8945a0SNathan Whitehorn #  define       DIRENT  struct dirent
554c8945a0SNathan Whitehorn # endif
564c8945a0SNathan Whitehorn 
574c8945a0SNathan Whitehorn #define EXT_WIDE 1
584c8945a0SNathan Whitehorn #define HDR_HIGH 1
594c8945a0SNathan Whitehorn #define BTN_HIGH (1 + 2 * MARGIN)	/* Ok/Cancel, also input-box */
604c8945a0SNathan Whitehorn #define MIN_HIGH (HDR_HIGH - MARGIN + (BTN_HIGH * 2) + 4 * MARGIN)
614c8945a0SNathan Whitehorn #define MIN_WIDE (2 * MAX(dlg_count_columns(d_label), dlg_count_columns(f_label)) + 6 * MARGIN + 2 * EXT_WIDE)
624c8945a0SNathan Whitehorn 
634c8945a0SNathan Whitehorn #define MOUSE_D (KEY_MAX + 0)
644c8945a0SNathan Whitehorn #define MOUSE_F (KEY_MAX + 10000)
654c8945a0SNathan Whitehorn #define MOUSE_T (KEY_MAX + 20000)
664c8945a0SNathan Whitehorn 
674c8945a0SNathan Whitehorn typedef enum {
684c8945a0SNathan Whitehorn     sDIRS = -3
694c8945a0SNathan Whitehorn     ,sFILES = -2
704c8945a0SNathan Whitehorn     ,sTEXT = -1
714c8945a0SNathan Whitehorn } STATES;
724c8945a0SNathan Whitehorn 
734c8945a0SNathan Whitehorn typedef struct {
744c8945a0SNathan Whitehorn     WINDOW *par;		/* parent window */
754c8945a0SNathan Whitehorn     WINDOW *win;		/* this window */
764c8945a0SNathan Whitehorn     int length;			/* length of the data[] array */
774c8945a0SNathan Whitehorn     int offset;			/* index of first item on screen */
784c8945a0SNathan Whitehorn     int choice;			/* index of the selection */
794c8945a0SNathan Whitehorn     int mousex;			/* base of mouse-code return-values */
804c8945a0SNathan Whitehorn     unsigned allocd;
814c8945a0SNathan Whitehorn     char **data;
824c8945a0SNathan Whitehorn } LIST;
834c8945a0SNathan Whitehorn 
844c8945a0SNathan Whitehorn typedef struct {
854c8945a0SNathan Whitehorn     int length;
864c8945a0SNathan Whitehorn     char **data;
874c8945a0SNathan Whitehorn } MATCH;
884c8945a0SNathan Whitehorn 
894c8945a0SNathan Whitehorn static void
init_list(LIST * list,WINDOW * par,WINDOW * win,int mousex)904c8945a0SNathan Whitehorn init_list(LIST * list, WINDOW *par, WINDOW *win, int mousex)
914c8945a0SNathan Whitehorn {
924c8945a0SNathan Whitehorn     list->par = par;
934c8945a0SNathan Whitehorn     list->win = win;
944c8945a0SNathan Whitehorn     list->length = 0;
954c8945a0SNathan Whitehorn     list->offset = 0;
964c8945a0SNathan Whitehorn     list->choice = 0;
974c8945a0SNathan Whitehorn     list->mousex = mousex;
984c8945a0SNathan Whitehorn     list->allocd = 0;
994c8945a0SNathan Whitehorn     list->data = 0;
1004c8945a0SNathan Whitehorn     dlg_mouse_mkbigregion(getbegy(win), getbegx(win),
1014c8945a0SNathan Whitehorn 			  getmaxy(win), getmaxx(win),
1024c8945a0SNathan Whitehorn 			  mousex, 1, 1, 1 /* by lines */ );
1034c8945a0SNathan Whitehorn }
1044c8945a0SNathan Whitehorn 
1054c8945a0SNathan Whitehorn static char *
leaf_of(char * path)1064c8945a0SNathan Whitehorn leaf_of(char *path)
1074c8945a0SNathan Whitehorn {
1084c8945a0SNathan Whitehorn     char *leaf = strrchr(path, '/');
1094c8945a0SNathan Whitehorn     if (leaf != 0)
1104c8945a0SNathan Whitehorn 	leaf++;
1114c8945a0SNathan Whitehorn     else
1124c8945a0SNathan Whitehorn 	leaf = path;
1134c8945a0SNathan Whitehorn     return leaf;
1144c8945a0SNathan Whitehorn }
1154c8945a0SNathan Whitehorn 
1164c8945a0SNathan Whitehorn static char *
data_of(LIST * list)1174c8945a0SNathan Whitehorn data_of(LIST * list)
1184c8945a0SNathan Whitehorn {
1194c8945a0SNathan Whitehorn     if (list != 0
1204c8945a0SNathan Whitehorn 	&& list->data != 0)
1214c8945a0SNathan Whitehorn 	return list->data[list->choice];
1224c8945a0SNathan Whitehorn     return 0;
1234c8945a0SNathan Whitehorn }
1244c8945a0SNathan Whitehorn 
1254c8945a0SNathan Whitehorn static void
free_list(LIST * list,int reinit)1264c8945a0SNathan Whitehorn free_list(LIST * list, int reinit)
1274c8945a0SNathan Whitehorn {
128*a96ef450SBaptiste Daroussin     if (list->data != 0) {
1294c8945a0SNathan Whitehorn 	int n;
1304c8945a0SNathan Whitehorn 
1314c8945a0SNathan Whitehorn 	for (n = 0; list->data[n] != 0; n++)
1324c8945a0SNathan Whitehorn 	    free(list->data[n]);
1334c8945a0SNathan Whitehorn 	free(list->data);
1344c8945a0SNathan Whitehorn 	list->data = 0;
1354c8945a0SNathan Whitehorn     }
1364c8945a0SNathan Whitehorn     if (reinit)
1374c8945a0SNathan Whitehorn 	init_list(list, list->par, list->win, list->mousex);
1384c8945a0SNathan Whitehorn }
1394c8945a0SNathan Whitehorn 
1404c8945a0SNathan Whitehorn static void
add_to_list(LIST * list,char * text)1414c8945a0SNathan Whitehorn add_to_list(LIST * list, char *text)
1424c8945a0SNathan Whitehorn {
1434c8945a0SNathan Whitehorn     unsigned need;
1444c8945a0SNathan Whitehorn 
1454c8945a0SNathan Whitehorn     need = (unsigned) (list->length + 1);
1464c8945a0SNathan Whitehorn     if (need + 1 > list->allocd) {
1474c8945a0SNathan Whitehorn 	list->allocd = 2 * (need + 1);
1484c8945a0SNathan Whitehorn 	if (list->data == 0) {
1494c8945a0SNathan Whitehorn 	    list->data = dlg_malloc(char *, list->allocd);
1504c8945a0SNathan Whitehorn 	} else {
1514c8945a0SNathan Whitehorn 	    list->data = dlg_realloc(char *, list->allocd, list->data);
1524c8945a0SNathan Whitehorn 	}
1534c8945a0SNathan Whitehorn 	assert_ptr(list->data, "add_to_list");
1544c8945a0SNathan Whitehorn     }
1554c8945a0SNathan Whitehorn     list->data[list->length++] = dlg_strclone(text);
1564c8945a0SNathan Whitehorn     list->data[list->length] = 0;
1574c8945a0SNathan Whitehorn }
1584c8945a0SNathan Whitehorn 
1594c8945a0SNathan Whitehorn static void
keep_visible(LIST * list)1604c8945a0SNathan Whitehorn keep_visible(LIST * list)
1614c8945a0SNathan Whitehorn {
1624c8945a0SNathan Whitehorn     int high = getmaxy(list->win);
1634c8945a0SNathan Whitehorn 
1644c8945a0SNathan Whitehorn     if (list->choice < list->offset) {
1654c8945a0SNathan Whitehorn 	list->offset = list->choice;
1664c8945a0SNathan Whitehorn     }
1674c8945a0SNathan Whitehorn     if (list->choice - list->offset >= high)
1684c8945a0SNathan Whitehorn 	list->offset = list->choice - high + 1;
1694c8945a0SNathan Whitehorn }
1704c8945a0SNathan Whitehorn 
1714c8945a0SNathan Whitehorn #define Value(c) (int)((c) & 0xff)
1724c8945a0SNathan Whitehorn 
1734c8945a0SNathan Whitehorn static int
find_choice(char * target,LIST * list)1744c8945a0SNathan Whitehorn find_choice(char *target, LIST * list)
1754c8945a0SNathan Whitehorn {
1764c8945a0SNathan Whitehorn     int choice = list->choice;
1774c8945a0SNathan Whitehorn 
1784c8945a0SNathan Whitehorn     if (*target == 0) {
1794c8945a0SNathan Whitehorn 	list->choice = 0;
1804c8945a0SNathan Whitehorn     } else {
181*a96ef450SBaptiste Daroussin 	int n;
182*a96ef450SBaptiste Daroussin 	int len_1, cmp_1;
183*a96ef450SBaptiste Daroussin 
1844c8945a0SNathan Whitehorn 	/* find the match with the longest length.  If more than one has the
1854c8945a0SNathan Whitehorn 	 * same length, choose the one with the closest match of the final
1864c8945a0SNathan Whitehorn 	 * character.
1874c8945a0SNathan Whitehorn 	 */
1884c8945a0SNathan Whitehorn 	len_1 = 0;
1894c8945a0SNathan Whitehorn 	cmp_1 = 256;
1904c8945a0SNathan Whitehorn 	for (n = 0; n < list->length; n++) {
1914c8945a0SNathan Whitehorn 	    char *a = target;
1924c8945a0SNathan Whitehorn 	    char *b = list->data[n];
193*a96ef450SBaptiste Daroussin 	    int len_2, cmp_2;
1944c8945a0SNathan Whitehorn 
1954c8945a0SNathan Whitehorn 	    len_2 = 0;
1964c8945a0SNathan Whitehorn 	    while ((*a != 0) && (*b != 0) && (*a == *b)) {
1974c8945a0SNathan Whitehorn 		a++;
1984c8945a0SNathan Whitehorn 		b++;
1994c8945a0SNathan Whitehorn 		len_2++;
2004c8945a0SNathan Whitehorn 	    }
2014c8945a0SNathan Whitehorn 	    cmp_2 = Value(*a) - Value(*b);
2024c8945a0SNathan Whitehorn 	    if (cmp_2 < 0)
2034c8945a0SNathan Whitehorn 		cmp_2 = -cmp_2;
2044c8945a0SNathan Whitehorn 	    if ((len_2 > len_1)
2054c8945a0SNathan Whitehorn 		|| (len_1 == len_2 && cmp_2 < cmp_1)) {
2064c8945a0SNathan Whitehorn 		len_1 = len_2;
2074c8945a0SNathan Whitehorn 		cmp_1 = cmp_2;
2084c8945a0SNathan Whitehorn 		list->choice = n;
2094c8945a0SNathan Whitehorn 	    }
2104c8945a0SNathan Whitehorn 	}
2114c8945a0SNathan Whitehorn     }
2124c8945a0SNathan Whitehorn     if (choice != list->choice) {
2134c8945a0SNathan Whitehorn 	keep_visible(list);
2144c8945a0SNathan Whitehorn     }
2154c8945a0SNathan Whitehorn     return (choice != list->choice);
2164c8945a0SNathan Whitehorn }
2174c8945a0SNathan Whitehorn 
2184c8945a0SNathan Whitehorn static void
display_list(LIST * list)2194c8945a0SNathan Whitehorn display_list(LIST * list)
2204c8945a0SNathan Whitehorn {
221*a96ef450SBaptiste Daroussin     if (list->win != 0) {
2224c8945a0SNathan Whitehorn 	int n;
2234c8945a0SNathan Whitehorn 	int x;
2244c8945a0SNathan Whitehorn 	int y;
2254c8945a0SNathan Whitehorn 	int top;
2264c8945a0SNathan Whitehorn 	int bottom;
2274c8945a0SNathan Whitehorn 
2284c8945a0SNathan Whitehorn 	dlg_attr_clear(list->win, getmaxy(list->win), getmaxx(list->win), item_attr);
2294c8945a0SNathan Whitehorn 	for (n = list->offset; n < list->length && list->data[n]; n++) {
2304c8945a0SNathan Whitehorn 	    y = n - list->offset;
2314c8945a0SNathan Whitehorn 	    if (y >= getmaxy(list->win))
2324c8945a0SNathan Whitehorn 		break;
2334c8945a0SNathan Whitehorn 	    (void) wmove(list->win, y, 0);
2344c8945a0SNathan Whitehorn 	    if (n == list->choice)
235f4f33ea0SBaptiste Daroussin 		dlg_attrset(list->win, item_selected_attr);
2364c8945a0SNathan Whitehorn 	    (void) waddstr(list->win, list->data[n]);
237f4f33ea0SBaptiste Daroussin 	    dlg_attrset(list->win, item_attr);
2384c8945a0SNathan Whitehorn 	}
239f4f33ea0SBaptiste Daroussin 	dlg_attrset(list->win, item_attr);
2404c8945a0SNathan Whitehorn 
2414c8945a0SNathan Whitehorn 	getparyx(list->win, y, x);
2424c8945a0SNathan Whitehorn 
2434c8945a0SNathan Whitehorn 	top = y - 1;
2444c8945a0SNathan Whitehorn 	bottom = y + getmaxy(list->win);
2454c8945a0SNathan Whitehorn 	dlg_draw_scrollbar(list->par,
2467a1c0d96SNathan Whitehorn 			   (long) list->offset,
2477a1c0d96SNathan Whitehorn 			   (long) list->offset,
2487a1c0d96SNathan Whitehorn 			   (long) (list->offset + getmaxy(list->win)),
2497a1c0d96SNathan Whitehorn 			   (long) (list->length),
2504c8945a0SNathan Whitehorn 			   x + 1,
2514c8945a0SNathan Whitehorn 			   x + getmaxx(list->win),
2524c8945a0SNathan Whitehorn 			   top,
2534c8945a0SNathan Whitehorn 			   bottom,
2542a3e3873SBaptiste Daroussin 			   menubox_border2_attr,
2554c8945a0SNathan Whitehorn 			   menubox_border_attr);
2564c8945a0SNathan Whitehorn 
2574c8945a0SNathan Whitehorn 	(void) wmove(list->win, list->choice - list->offset, 0);
2584c8945a0SNathan Whitehorn 	(void) wnoutrefresh(list->win);
2594c8945a0SNathan Whitehorn     }
2604c8945a0SNathan Whitehorn }
2614c8945a0SNathan Whitehorn 
2624c8945a0SNathan Whitehorn /* FIXME: see arrows.c
2634c8945a0SNathan Whitehorn  * This workaround is used to allow two lists to have scroll-tabs at the same
2644c8945a0SNathan Whitehorn  * time, by reassigning their return-values to be different.  Just for
2654c8945a0SNathan Whitehorn  * readability, we use the names of keys with similar connotations, though all
2664c8945a0SNathan Whitehorn  * that is really required is that they're distinct, so we can put them in a
2674c8945a0SNathan Whitehorn  * switch statement.
2684c8945a0SNathan Whitehorn  */
269*a96ef450SBaptiste Daroussin #if USE_MOUSE
2704c8945a0SNathan Whitehorn static void
fix_arrows(LIST * list)2714c8945a0SNathan Whitehorn fix_arrows(LIST * list)
2724c8945a0SNathan Whitehorn {
273*a96ef450SBaptiste Daroussin     if (list->win != 0) {
2744c8945a0SNathan Whitehorn 	int x;
2754c8945a0SNathan Whitehorn 	int y;
2764c8945a0SNathan Whitehorn 	int top;
2772a3e3873SBaptiste Daroussin 	int right;
2784c8945a0SNathan Whitehorn 	int bottom;
2794c8945a0SNathan Whitehorn 
2804c8945a0SNathan Whitehorn 	getparyx(list->win, y, x);
2814c8945a0SNathan Whitehorn 	top = y - 1;
2822a3e3873SBaptiste Daroussin 	right = getmaxx(list->win);
2834c8945a0SNathan Whitehorn 	bottom = y + getmaxy(list->win);
2844c8945a0SNathan Whitehorn 
2852a3e3873SBaptiste Daroussin 	mouse_mkbutton(top, x, right,
2864c8945a0SNathan Whitehorn 		       ((list->mousex == MOUSE_D)
2874c8945a0SNathan Whitehorn 			? KEY_PREVIOUS
2884c8945a0SNathan Whitehorn 			: KEY_PPAGE));
2892a3e3873SBaptiste Daroussin 	mouse_mkbutton(bottom, x, right,
2904c8945a0SNathan Whitehorn 		       ((list->mousex == MOUSE_D)
2914c8945a0SNathan Whitehorn 			? KEY_NEXT
2924c8945a0SNathan Whitehorn 			: KEY_NPAGE));
2934c8945a0SNathan Whitehorn     }
2944c8945a0SNathan Whitehorn }
2954c8945a0SNathan Whitehorn 
296*a96ef450SBaptiste Daroussin #else
297*a96ef450SBaptiste Daroussin #define fix_arrows(list)	/* nothing */
298*a96ef450SBaptiste Daroussin #endif
299*a96ef450SBaptiste Daroussin 
300f4f33ea0SBaptiste Daroussin static bool
show_list(char * target,LIST * list,bool keep)301f4f33ea0SBaptiste Daroussin show_list(char *target, LIST * list, bool keep)
3024c8945a0SNathan Whitehorn {
303f4f33ea0SBaptiste Daroussin     bool changed = keep || find_choice(target, list);
3044c8945a0SNathan Whitehorn     display_list(list);
3054c8945a0SNathan Whitehorn     return changed;
3064c8945a0SNathan Whitehorn }
3074c8945a0SNathan Whitehorn 
3084c8945a0SNathan Whitehorn /*
3094c8945a0SNathan Whitehorn  * Highlight the closest match to 'target' in the given list, setting offset
3104c8945a0SNathan Whitehorn  * to match.
3114c8945a0SNathan Whitehorn  */
312f4f33ea0SBaptiste Daroussin static bool
show_both_lists(char * input,LIST * d_list,LIST * f_list,bool keep)313f4f33ea0SBaptiste Daroussin show_both_lists(char *input, LIST * d_list, LIST * f_list, bool keep)
3144c8945a0SNathan Whitehorn {
3154c8945a0SNathan Whitehorn     char *leaf = leaf_of(input);
3164c8945a0SNathan Whitehorn 
317f4f33ea0SBaptiste Daroussin     return show_list(leaf, d_list, keep) || show_list(leaf, f_list, keep);
3184c8945a0SNathan Whitehorn }
3194c8945a0SNathan Whitehorn 
3204c8945a0SNathan Whitehorn /*
3214c8945a0SNathan Whitehorn  * Move up/down in the given list
3224c8945a0SNathan Whitehorn  */
3234c8945a0SNathan Whitehorn static bool
change_list(int choice,LIST * list)3244c8945a0SNathan Whitehorn change_list(int choice, LIST * list)
3254c8945a0SNathan Whitehorn {
3264c8945a0SNathan Whitehorn     if (data_of(list) != 0) {
3274c8945a0SNathan Whitehorn 	int last = list->length - 1;
3284c8945a0SNathan Whitehorn 
3294c8945a0SNathan Whitehorn 	choice += list->choice;
3304c8945a0SNathan Whitehorn 	if (choice < 0)
3314c8945a0SNathan Whitehorn 	    choice = 0;
3324c8945a0SNathan Whitehorn 	if (choice > last)
3334c8945a0SNathan Whitehorn 	    choice = last;
3344c8945a0SNathan Whitehorn 	list->choice = choice;
3354c8945a0SNathan Whitehorn 	keep_visible(list);
3364c8945a0SNathan Whitehorn 	display_list(list);
3374c8945a0SNathan Whitehorn 	return TRUE;
3384c8945a0SNathan Whitehorn     }
3394c8945a0SNathan Whitehorn     return FALSE;
3404c8945a0SNathan Whitehorn }
3414c8945a0SNathan Whitehorn 
3424c8945a0SNathan Whitehorn static void
scroll_list(int direction,LIST * list)3434c8945a0SNathan Whitehorn scroll_list(int direction, LIST * list)
3444c8945a0SNathan Whitehorn {
3454c8945a0SNathan Whitehorn     if (data_of(list) != 0) {
3464c8945a0SNathan Whitehorn 	int length = getmaxy(list->win);
3474c8945a0SNathan Whitehorn 	if (change_list(direction * length, list))
3484c8945a0SNathan Whitehorn 	    return;
3494c8945a0SNathan Whitehorn     }
3504c8945a0SNathan Whitehorn     beep();
3514c8945a0SNathan Whitehorn }
3524c8945a0SNathan Whitehorn 
3534c8945a0SNathan Whitehorn static int
compar(const void * a,const void * b)3544c8945a0SNathan Whitehorn compar(const void *a, const void *b)
3554c8945a0SNathan Whitehorn {
3564c8945a0SNathan Whitehorn     return strcmp(*(const char *const *) a, *(const char *const *) b);
3574c8945a0SNathan Whitehorn }
3584c8945a0SNathan Whitehorn 
3594c8945a0SNathan Whitehorn static void
match(char * name,LIST * d_list,LIST * f_list,MATCH * match_list)3604c8945a0SNathan Whitehorn match(char *name, LIST * d_list, LIST * f_list, MATCH * match_list)
3614c8945a0SNathan Whitehorn {
3624c8945a0SNathan Whitehorn     char *test = leaf_of(name);
3634c8945a0SNathan Whitehorn     size_t test_len = strlen(test);
3644c8945a0SNathan Whitehorn     char **matches = dlg_malloc(char *, (size_t) (d_list->length + f_list->length));
3654c8945a0SNathan Whitehorn     size_t data_len = 0;
366*a96ef450SBaptiste Daroussin 
367*a96ef450SBaptiste Daroussin     if (matches != 0) {
3684c8945a0SNathan Whitehorn 	int i;
369*a96ef450SBaptiste Daroussin 	char **new_ptr;
370*a96ef450SBaptiste Daroussin 
3714c8945a0SNathan Whitehorn 	for (i = 2; i < d_list->length; i++) {
3724c8945a0SNathan Whitehorn 	    if (strncmp(test, d_list->data[i], test_len) == 0) {
3734c8945a0SNathan Whitehorn 		matches[data_len++] = d_list->data[i];
3744c8945a0SNathan Whitehorn 	    }
3754c8945a0SNathan Whitehorn 	}
3764c8945a0SNathan Whitehorn 	for (i = 0; i < f_list->length; i++) {
3774c8945a0SNathan Whitehorn 	    if (strncmp(test, f_list->data[i], test_len) == 0) {
3784c8945a0SNathan Whitehorn 		matches[data_len++] = f_list->data[i];
3794c8945a0SNathan Whitehorn 	    }
3804c8945a0SNathan Whitehorn 	}
381*a96ef450SBaptiste Daroussin 	if ((new_ptr = dlg_realloc(char *, data_len + 1, matches)) != 0) {
382*a96ef450SBaptiste Daroussin 	    matches = new_ptr;
383*a96ef450SBaptiste Daroussin 	} else {
384*a96ef450SBaptiste Daroussin 	    free(matches);
385*a96ef450SBaptiste Daroussin 	    matches = 0;
386*a96ef450SBaptiste Daroussin 	    data_len = 0;
387*a96ef450SBaptiste Daroussin 	}
388*a96ef450SBaptiste Daroussin     }
3894c8945a0SNathan Whitehorn     match_list->data = matches;
3904c8945a0SNathan Whitehorn     match_list->length = (int) data_len;
3914c8945a0SNathan Whitehorn }
3924c8945a0SNathan Whitehorn 
3934c8945a0SNathan Whitehorn static void
free_match(MATCH * match_list)3944c8945a0SNathan Whitehorn free_match(MATCH * match_list)
3954c8945a0SNathan Whitehorn {
3964c8945a0SNathan Whitehorn     free(match_list->data);
3974c8945a0SNathan Whitehorn     match_list->length = 0;
3984c8945a0SNathan Whitehorn }
3994c8945a0SNathan Whitehorn 
4004c8945a0SNathan Whitehorn static int
complete(char * name,LIST * d_list,LIST * f_list,char ** buff_ptr)4014c8945a0SNathan Whitehorn complete(char *name, LIST * d_list, LIST * f_list, char **buff_ptr)
4024c8945a0SNathan Whitehorn {
4034c8945a0SNathan Whitehorn     MATCH match_list;
4044c8945a0SNathan Whitehorn     char *test;
4054c8945a0SNathan Whitehorn     size_t test_len;
4064c8945a0SNathan Whitehorn     size_t i;
4074c8945a0SNathan Whitehorn     char *buff;
4084c8945a0SNathan Whitehorn 
4094c8945a0SNathan Whitehorn     match(name, d_list, f_list, &match_list);
4104c8945a0SNathan Whitehorn     if (match_list.length == 0) {
411*a96ef450SBaptiste Daroussin 	free(match_list.data);
4124c8945a0SNathan Whitehorn 	*buff_ptr = NULL;
4134c8945a0SNathan Whitehorn 	return 0;
4144c8945a0SNathan Whitehorn     }
4154c8945a0SNathan Whitehorn 
4164c8945a0SNathan Whitehorn     test = match_list.data[0];
4174c8945a0SNathan Whitehorn     test_len = strlen(test);
4184c8945a0SNathan Whitehorn     buff = dlg_malloc(char, test_len + 2);
4194c8945a0SNathan Whitehorn     if (match_list.length == 1) {
4204c8945a0SNathan Whitehorn 	strcpy(buff, test);
4214c8945a0SNathan Whitehorn 	i = test_len;
4224c8945a0SNathan Whitehorn 	if (test == data_of(d_list)) {
4234c8945a0SNathan Whitehorn 	    buff[test_len] = '/';
4244c8945a0SNathan Whitehorn 	    i++;
4254c8945a0SNathan Whitehorn 	}
4264c8945a0SNathan Whitehorn     } else {
427*a96ef450SBaptiste Daroussin 	int j;
428*a96ef450SBaptiste Daroussin 
4294c8945a0SNathan Whitehorn 	for (i = 0; i < test_len; i++) {
4304c8945a0SNathan Whitehorn 	    char test_char = test[i];
4314c8945a0SNathan Whitehorn 	    if (test_char == '\0')
4324c8945a0SNathan Whitehorn 		break;
4334c8945a0SNathan Whitehorn 	    for (j = 0; j < match_list.length; j++) {
4344c8945a0SNathan Whitehorn 		if (match_list.data[j][i] != test_char) {
4354c8945a0SNathan Whitehorn 		    break;
4364c8945a0SNathan Whitehorn 		}
4374c8945a0SNathan Whitehorn 	    }
4384c8945a0SNathan Whitehorn 	    if (j == match_list.length) {
4394c8945a0SNathan Whitehorn 		(buff)[i] = test_char;
4404c8945a0SNathan Whitehorn 	    } else
4414c8945a0SNathan Whitehorn 		break;
4424c8945a0SNathan Whitehorn 	}
4434c8945a0SNathan Whitehorn 	buff = dlg_realloc(char, i + 1, buff);
4444c8945a0SNathan Whitehorn     }
4454c8945a0SNathan Whitehorn     free_match(&match_list);
4464c8945a0SNathan Whitehorn     buff[i] = '\0';
4474c8945a0SNathan Whitehorn     *buff_ptr = buff;
4484c8945a0SNathan Whitehorn     return (i != 0);
4494c8945a0SNathan Whitehorn }
4504c8945a0SNathan Whitehorn 
4514c8945a0SNathan Whitehorn static bool
fill_lists(char * current,char * input,LIST * d_list,LIST * f_list,bool keep)452f4f33ea0SBaptiste Daroussin fill_lists(char *current, char *input, LIST * d_list, LIST * f_list, bool keep)
4534c8945a0SNathan Whitehorn {
4542a3e3873SBaptiste Daroussin     bool result = TRUE;
4552a3e3873SBaptiste Daroussin     bool rescan = FALSE;
4564c8945a0SNathan Whitehorn     struct stat sb;
4574c8945a0SNathan Whitehorn     int n;
4584c8945a0SNathan Whitehorn     char path[MAX_LEN + 1];
4594c8945a0SNathan Whitehorn 
4604c8945a0SNathan Whitehorn     /* check if we've updated the lists */
4614c8945a0SNathan Whitehorn     for (n = 0; current[n] && input[n]; n++) {
4624c8945a0SNathan Whitehorn 	if (current[n] != input[n])
4634c8945a0SNathan Whitehorn 	    break;
4644c8945a0SNathan Whitehorn     }
4652a3e3873SBaptiste Daroussin 
4662a3e3873SBaptiste Daroussin     if (current[n] == input[n]) {
4672a3e3873SBaptiste Daroussin 	result = FALSE;
4682a3e3873SBaptiste Daroussin 	rescan = (n == 0 && d_list->length == 0);
4692a3e3873SBaptiste Daroussin     } else if (strchr(current + n, '/') == 0
4704c8945a0SNathan Whitehorn 	       && strchr(input + n, '/') == 0) {
4712a3e3873SBaptiste Daroussin 	result = show_both_lists(input, d_list, f_list, keep);
4722a3e3873SBaptiste Daroussin     } else {
4732a3e3873SBaptiste Daroussin 	rescan = TRUE;
4744c8945a0SNathan Whitehorn     }
4754c8945a0SNathan Whitehorn 
4762a3e3873SBaptiste Daroussin     if (rescan) {
477*a96ef450SBaptiste Daroussin 	DIR *dp;
4782a3e3873SBaptiste Daroussin 	size_t have = strlen(input);
479*a96ef450SBaptiste Daroussin 	char *leaf;
4802a3e3873SBaptiste Daroussin 
4812a3e3873SBaptiste Daroussin 	if (have > MAX_LEN)
4822a3e3873SBaptiste Daroussin 	    have = MAX_LEN;
4832a3e3873SBaptiste Daroussin 	memcpy(current, input, have);
4842a3e3873SBaptiste Daroussin 	current[have] = '\0';
4854c8945a0SNathan Whitehorn 
4864c8945a0SNathan Whitehorn 	/* refill the lists */
4874c8945a0SNathan Whitehorn 	free_list(d_list, TRUE);
4884c8945a0SNathan Whitehorn 	free_list(f_list, TRUE);
4892a3e3873SBaptiste Daroussin 	memcpy(path, current, have);
4902a3e3873SBaptiste Daroussin 	path[have] = '\0';
4914c8945a0SNathan Whitehorn 	if ((leaf = strrchr(path, '/')) != 0) {
4924c8945a0SNathan Whitehorn 	    *++leaf = 0;
4934c8945a0SNathan Whitehorn 	} else {
4944c8945a0SNathan Whitehorn 	    strcpy(path, "./");
4954c8945a0SNathan Whitehorn 	    leaf = path + strlen(path);
4964c8945a0SNathan Whitehorn 	}
497f4f33ea0SBaptiste Daroussin 	DLG_TRACE(("opendir '%s'\n", path));
4984c8945a0SNathan Whitehorn 	if ((dp = opendir(path)) != 0) {
499*a96ef450SBaptiste Daroussin 	    DIRENT *de;
500*a96ef450SBaptiste Daroussin 
5014c8945a0SNathan Whitehorn 	    while ((de = readdir(dp)) != 0) {
502f4f33ea0SBaptiste Daroussin 		size_t len = NAMLEN(de);
503f4f33ea0SBaptiste Daroussin 		if (len == 0 || (len + have + 2) >= MAX_LEN)
504f4f33ea0SBaptiste Daroussin 		    continue;
505f4f33ea0SBaptiste Daroussin 		memcpy(leaf, de->d_name, len);
506f4f33ea0SBaptiste Daroussin 		leaf[len] = '\0';
5074c8945a0SNathan Whitehorn 		if (stat(path, &sb) == 0) {
5084c8945a0SNathan Whitehorn 		    if ((sb.st_mode & S_IFMT) == S_IFDIR)
5094c8945a0SNathan Whitehorn 			add_to_list(d_list, leaf);
5104c8945a0SNathan Whitehorn 		    else if (f_list->win)
5114c8945a0SNathan Whitehorn 			add_to_list(f_list, leaf);
5124c8945a0SNathan Whitehorn 		}
5134c8945a0SNathan Whitehorn 	    }
5144c8945a0SNathan Whitehorn 	    (void) closedir(dp);
5154c8945a0SNathan Whitehorn 	    /* sort the lists */
5162a3e3873SBaptiste Daroussin 	    if (d_list->data != 0 && d_list->length > 1) {
5174c8945a0SNathan Whitehorn 		qsort(d_list->data,
5184c8945a0SNathan Whitehorn 		      (size_t) d_list->length,
5194c8945a0SNathan Whitehorn 		      sizeof(d_list->data[0]),
5204c8945a0SNathan Whitehorn 		      compar);
5212a3e3873SBaptiste Daroussin 	    }
5222a3e3873SBaptiste Daroussin 	    if (f_list->data != 0 && f_list->length > 1) {
5234c8945a0SNathan Whitehorn 		qsort(f_list->data,
5244c8945a0SNathan Whitehorn 		      (size_t) f_list->length,
5254c8945a0SNathan Whitehorn 		      sizeof(f_list->data[0]),
5264c8945a0SNathan Whitehorn 		      compar);
5274c8945a0SNathan Whitehorn 	    }
5282a3e3873SBaptiste Daroussin 	}
5294c8945a0SNathan Whitehorn 
5304c8945a0SNathan Whitehorn 	(void) show_both_lists(input, d_list, f_list, FALSE);
5314c8945a0SNathan Whitehorn 	d_list->offset = d_list->choice;
5324c8945a0SNathan Whitehorn 	f_list->offset = f_list->choice;
5332a3e3873SBaptiste Daroussin 	result = TRUE;
5342a3e3873SBaptiste Daroussin     }
5352a3e3873SBaptiste Daroussin     return result;
5364c8945a0SNathan Whitehorn }
5374c8945a0SNathan Whitehorn 
5384c8945a0SNathan Whitehorn static bool
usable_state(int state,LIST * dirs,LIST * files)5394c8945a0SNathan Whitehorn usable_state(int state, LIST * dirs, LIST * files)
5404c8945a0SNathan Whitehorn {
5414c8945a0SNathan Whitehorn     bool result;
5424c8945a0SNathan Whitehorn 
5434c8945a0SNathan Whitehorn     switch (state) {
5444c8945a0SNathan Whitehorn     case sDIRS:
5454c8945a0SNathan Whitehorn 	result = (dirs->win != 0) && (data_of(dirs) != 0);
5464c8945a0SNathan Whitehorn 	break;
5474c8945a0SNathan Whitehorn     case sFILES:
5484c8945a0SNathan Whitehorn 	result = (files->win != 0) && (data_of(files) != 0);
5494c8945a0SNathan Whitehorn 	break;
5504c8945a0SNathan Whitehorn     default:
5514c8945a0SNathan Whitehorn 	result = TRUE;
5524c8945a0SNathan Whitehorn 	break;
5534c8945a0SNathan Whitehorn     }
5544c8945a0SNathan Whitehorn     return result;
5554c8945a0SNathan Whitehorn }
5564c8945a0SNathan Whitehorn 
5574c8945a0SNathan Whitehorn #define which_list() ((state == sFILES) \
5584c8945a0SNathan Whitehorn 			? &f_list \
5594c8945a0SNathan Whitehorn 			: ((state == sDIRS) \
5604c8945a0SNathan Whitehorn 			  ? &d_list \
5614c8945a0SNathan Whitehorn 			  : 0))
5624c8945a0SNathan Whitehorn #define NAVIGATE_BINDINGS \
5634c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ), \
5644c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ), \
5654c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ), \
5664c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_DOWN ), \
5674c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  CHR_NEXT ), \
5684c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_NEXT ), \
5694c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  CHR_PREVIOUS ), \
5704c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_UP ), \
5714c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_PAGE_NEXT,  KEY_NPAGE ), \
5724c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_PAGE_PREV,  KEY_PPAGE )
5734c8945a0SNathan Whitehorn 
5744c8945a0SNathan Whitehorn /*
5754c8945a0SNathan Whitehorn  * Display a dialog box for entering a filename
5764c8945a0SNathan Whitehorn  */
5774c8945a0SNathan Whitehorn static int
dlg_fselect(const char * title,const char * path,int height,int width,int dselect)5787a1c0d96SNathan Whitehorn dlg_fselect(const char *title, const char *path, int height, int width, int dselect)
5794c8945a0SNathan Whitehorn {
5804c8945a0SNathan Whitehorn     /* *INDENT-OFF* */
5814c8945a0SNathan Whitehorn     static DLG_KEYS_BINDING binding[] = {
582682c9e0fSNathan Whitehorn 	HELPKEY_BINDINGS,
5834c8945a0SNathan Whitehorn 	ENTERKEY_BINDINGS,
5844c8945a0SNathan Whitehorn 	NAVIGATE_BINDINGS,
585f4f33ea0SBaptiste Daroussin 	TOGGLEKEY_BINDINGS,
5864c8945a0SNathan Whitehorn 	END_KEYS_BINDING
5874c8945a0SNathan Whitehorn     };
5884c8945a0SNathan Whitehorn     static DLG_KEYS_BINDING binding2[] = {
5894c8945a0SNathan Whitehorn 	INPUTSTR_BINDINGS,
590682c9e0fSNathan Whitehorn 	HELPKEY_BINDINGS,
5914c8945a0SNathan Whitehorn 	ENTERKEY_BINDINGS,
5924c8945a0SNathan Whitehorn 	NAVIGATE_BINDINGS,
593f4f33ea0SBaptiste Daroussin 	TOGGLEKEY_BINDINGS,
5944c8945a0SNathan Whitehorn 	END_KEYS_BINDING
5954c8945a0SNathan Whitehorn     };
5964c8945a0SNathan Whitehorn     /* *INDENT-ON* */
5974c8945a0SNathan Whitehorn 
5984c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
5994c8945a0SNathan Whitehorn     int old_height = height;
6004c8945a0SNathan Whitehorn     int old_width = width;
6014c8945a0SNathan Whitehorn     bool resized = FALSE;
6024c8945a0SNathan Whitehorn #endif
6034c8945a0SNathan Whitehorn     int tbox_y, tbox_x, tbox_width, tbox_height;
6044c8945a0SNathan Whitehorn     int dbox_y, dbox_x, dbox_width, dbox_height;
6054c8945a0SNathan Whitehorn     int fbox_y, fbox_x, fbox_width, fbox_height;
6064c8945a0SNathan Whitehorn     int show_buttons = TRUE;
6074c8945a0SNathan Whitehorn     int offset = 0;
6084c8945a0SNathan Whitehorn     int key = 0;
6094c8945a0SNathan Whitehorn     int fkey = FALSE;
6104c8945a0SNathan Whitehorn     int code;
6114c8945a0SNathan Whitehorn     int result = DLG_EXIT_UNKNOWN;
6122a3e3873SBaptiste Daroussin     int state = dialog_vars.default_button >= 0 ? dlg_default_button() : sTEXT;
6132a3e3873SBaptiste Daroussin     int button;
614f4f33ea0SBaptiste Daroussin     bool first = (state == sTEXT);
615f4f33ea0SBaptiste Daroussin     bool first_trace = TRUE;
6164c8945a0SNathan Whitehorn     char *input;
6174c8945a0SNathan Whitehorn     char *completed;
6184c8945a0SNathan Whitehorn     char current[MAX_LEN + 1];
6194c8945a0SNathan Whitehorn     WINDOW *dialog = 0;
6204c8945a0SNathan Whitehorn     WINDOW *w_text = 0;
6214c8945a0SNathan Whitehorn     WINDOW *w_work = 0;
6224c8945a0SNathan Whitehorn     const char **buttons = dlg_ok_labels();
6237a1c0d96SNathan Whitehorn     const char *d_label = _("Directories");
6247a1c0d96SNathan Whitehorn     const char *f_label = _("Files");
6252a3e3873SBaptiste Daroussin     char *partial = 0;
6264c8945a0SNathan Whitehorn     int min_wide = MIN_WIDE;
6274c8945a0SNathan Whitehorn     int min_items = height ? 0 : 4;
6284c8945a0SNathan Whitehorn     LIST d_list, f_list;
6294c8945a0SNathan Whitehorn 
630f4f33ea0SBaptiste Daroussin     DLG_TRACE(("# %s args:\n", dselect ? "dselect" : "fselect"));
631f4f33ea0SBaptiste Daroussin     DLG_TRACE2S("title", title);
632f4f33ea0SBaptiste Daroussin     DLG_TRACE2S("path", path);
633f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("height", height);
634f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("width", width);
635f4f33ea0SBaptiste Daroussin 
6364c8945a0SNathan Whitehorn     dlg_does_output();
6374c8945a0SNathan Whitehorn 
6384c8945a0SNathan Whitehorn     /* Set up the initial value */
6394c8945a0SNathan Whitehorn     input = dlg_set_result(path);
6404c8945a0SNathan Whitehorn     offset = (int) strlen(input);
6414c8945a0SNathan Whitehorn     *current = 0;
6424c8945a0SNathan Whitehorn 
6434c8945a0SNathan Whitehorn     dlg_button_layout(buttons, &min_wide);
6444c8945a0SNathan Whitehorn 
6454c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
6464c8945a0SNathan Whitehorn   retry:
6474c8945a0SNathan Whitehorn #endif
648*a96ef450SBaptiste Daroussin     dlg_auto_size(title, "", &height, &width, MIN_HIGH + min_items, min_wide);
649*a96ef450SBaptiste Daroussin 
6504c8945a0SNathan Whitehorn     dlg_print_size(height, width);
6514c8945a0SNathan Whitehorn     dlg_ctl_size(height, width);
6524c8945a0SNathan Whitehorn 
6534c8945a0SNathan Whitehorn     dialog = dlg_new_window(height, width,
6544c8945a0SNathan Whitehorn 			    dlg_box_y_ordinate(height),
6554c8945a0SNathan Whitehorn 			    dlg_box_x_ordinate(width));
6564c8945a0SNathan Whitehorn     dlg_register_window(dialog, "fselect", binding);
6574c8945a0SNathan Whitehorn     dlg_register_buttons(dialog, "fselect", buttons);
6584c8945a0SNathan Whitehorn 
6594c8945a0SNathan Whitehorn     dlg_mouse_setbase(0, 0);
6604c8945a0SNathan Whitehorn 
6612a3e3873SBaptiste Daroussin     dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr);
6622a3e3873SBaptiste Daroussin     dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr);
6634c8945a0SNathan Whitehorn     dlg_draw_title(dialog, title);
6644c8945a0SNathan Whitehorn 
665f4f33ea0SBaptiste Daroussin     dlg_attrset(dialog, dialog_attr);
6664c8945a0SNathan Whitehorn 
6674c8945a0SNathan Whitehorn     /* Draw the input field box */
6684c8945a0SNathan Whitehorn     tbox_height = 1;
6694c8945a0SNathan Whitehorn     tbox_width = width - (4 * MARGIN + 2);
6704c8945a0SNathan Whitehorn     tbox_y = height - (BTN_HIGH * 2) + MARGIN;
6714c8945a0SNathan Whitehorn     tbox_x = (width - tbox_width) / 2;
6724c8945a0SNathan Whitehorn 
673*a96ef450SBaptiste Daroussin     w_text = dlg_der_window(dialog, tbox_height, tbox_width, tbox_y, tbox_x);
6742a3e3873SBaptiste Daroussin     if (w_text == 0) {
6752a3e3873SBaptiste Daroussin 	result = DLG_EXIT_ERROR;
6762a3e3873SBaptiste Daroussin 	goto finish;
6772a3e3873SBaptiste Daroussin     }
6784c8945a0SNathan Whitehorn 
6794c8945a0SNathan Whitehorn     dlg_draw_box(dialog, tbox_y - MARGIN, tbox_x - MARGIN,
6804c8945a0SNathan Whitehorn 		 (2 * MARGIN + 1), tbox_width + (MARGIN + EXT_WIDE),
6812a3e3873SBaptiste Daroussin 		 menubox_border_attr, menubox_border2_attr);
6824c8945a0SNathan Whitehorn     dlg_mouse_mkbigregion(getbegy(dialog) + tbox_y - MARGIN,
6834c8945a0SNathan Whitehorn 			  getbegx(dialog) + tbox_x - MARGIN,
6844c8945a0SNathan Whitehorn 			  1 + (2 * MARGIN),
6854c8945a0SNathan Whitehorn 			  tbox_width + (MARGIN + EXT_WIDE),
6864c8945a0SNathan Whitehorn 			  MOUSE_T, 1, 1, 3 /* doesn't matter */ );
6874c8945a0SNathan Whitehorn 
6882a3e3873SBaptiste Daroussin     dlg_register_window(w_text, "fselect2", binding2);
6894c8945a0SNathan Whitehorn 
6904c8945a0SNathan Whitehorn     /* Draw the directory listing box */
6914c8945a0SNathan Whitehorn     if (dselect)
6924c8945a0SNathan Whitehorn 	dbox_width = (width - (6 * MARGIN));
6934c8945a0SNathan Whitehorn     else
6944c8945a0SNathan Whitehorn 	dbox_width = (width - (6 * MARGIN + 2 * EXT_WIDE)) / 2;
6954c8945a0SNathan Whitehorn     dbox_height = height - MIN_HIGH;
6964c8945a0SNathan Whitehorn     dbox_y = (2 * MARGIN + 1);
6974c8945a0SNathan Whitehorn     dbox_x = tbox_x;
6984c8945a0SNathan Whitehorn 
699*a96ef450SBaptiste Daroussin     w_work = dlg_der_window(dialog, dbox_height, dbox_width, dbox_y, dbox_x);
7002a3e3873SBaptiste Daroussin     if (w_work == 0) {
7012a3e3873SBaptiste Daroussin 	result = DLG_EXIT_ERROR;
7022a3e3873SBaptiste Daroussin 	goto finish;
7032a3e3873SBaptiste Daroussin     }
7044c8945a0SNathan Whitehorn 
7052a3e3873SBaptiste Daroussin     (void) mvwaddstr(dialog, dbox_y - (MARGIN + 1), dbox_x - MARGIN, d_label);
7064c8945a0SNathan Whitehorn     dlg_draw_box(dialog,
7074c8945a0SNathan Whitehorn 		 dbox_y - MARGIN, dbox_x - MARGIN,
7084c8945a0SNathan Whitehorn 		 dbox_height + (MARGIN + 1), dbox_width + (MARGIN + 1),
7092a3e3873SBaptiste Daroussin 		 menubox_border_attr, menubox_border2_attr);
7104c8945a0SNathan Whitehorn     init_list(&d_list, dialog, w_work, MOUSE_D);
7114c8945a0SNathan Whitehorn 
7124c8945a0SNathan Whitehorn     if (!dselect) {
7134c8945a0SNathan Whitehorn 	/* Draw the filename listing box */
7144c8945a0SNathan Whitehorn 	fbox_height = dbox_height;
7154c8945a0SNathan Whitehorn 	fbox_width = dbox_width;
7164c8945a0SNathan Whitehorn 	fbox_y = dbox_y;
7174c8945a0SNathan Whitehorn 	fbox_x = tbox_x + dbox_width + (2 * MARGIN);
7184c8945a0SNathan Whitehorn 
719*a96ef450SBaptiste Daroussin 	w_work = dlg_der_window(dialog, fbox_height, fbox_width, fbox_y, fbox_x);
7202a3e3873SBaptiste Daroussin 	if (w_work == 0) {
7212a3e3873SBaptiste Daroussin 	    result = DLG_EXIT_ERROR;
7222a3e3873SBaptiste Daroussin 	    goto finish;
7232a3e3873SBaptiste Daroussin 	}
7244c8945a0SNathan Whitehorn 
7252a3e3873SBaptiste Daroussin 	(void) mvwaddstr(dialog, fbox_y - (MARGIN + 1), fbox_x - MARGIN, f_label);
7264c8945a0SNathan Whitehorn 	dlg_draw_box(dialog,
7274c8945a0SNathan Whitehorn 		     fbox_y - MARGIN, fbox_x - MARGIN,
7284c8945a0SNathan Whitehorn 		     fbox_height + (MARGIN + 1), fbox_width + (MARGIN + 1),
7292a3e3873SBaptiste Daroussin 		     menubox_border_attr, menubox_border2_attr);
7304c8945a0SNathan Whitehorn 	init_list(&f_list, dialog, w_work, MOUSE_F);
7314c8945a0SNathan Whitehorn     } else {
7324c8945a0SNathan Whitehorn 	memset(&f_list, 0, sizeof(f_list));
7334c8945a0SNathan Whitehorn     }
7344c8945a0SNathan Whitehorn 
7354c8945a0SNathan Whitehorn     while (result == DLG_EXIT_UNKNOWN) {
7364c8945a0SNathan Whitehorn 
7374c8945a0SNathan Whitehorn 	if (fill_lists(current, input, &d_list, &f_list, state < sTEXT))
7384c8945a0SNathan Whitehorn 	    show_buttons = TRUE;
7394c8945a0SNathan Whitehorn 
7404c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
7414c8945a0SNathan Whitehorn 	if (resized) {
7424c8945a0SNathan Whitehorn 	    resized = FALSE;
7434c8945a0SNathan Whitehorn 	    dlg_show_string(w_text, input, offset, inputbox_attr,
744f4f33ea0SBaptiste Daroussin 			    0, 0, tbox_width, FALSE, first);
7454c8945a0SNathan Whitehorn 	}
7464c8945a0SNathan Whitehorn #endif
7474c8945a0SNathan Whitehorn 
7484c8945a0SNathan Whitehorn 	/*
7494c8945a0SNathan Whitehorn 	 * The last field drawn determines where the cursor is shown:
7504c8945a0SNathan Whitehorn 	 */
7514c8945a0SNathan Whitehorn 	if (show_buttons) {
7524c8945a0SNathan Whitehorn 	    show_buttons = FALSE;
7534c8945a0SNathan Whitehorn 	    button = (state < 0) ? 0 : state;
7544c8945a0SNathan Whitehorn 	    dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width);
7554c8945a0SNathan Whitehorn 	}
7562a3e3873SBaptiste Daroussin 
7572a3e3873SBaptiste Daroussin 	if (first_trace) {
7582a3e3873SBaptiste Daroussin 	    first_trace = FALSE;
7592a3e3873SBaptiste Daroussin 	    dlg_trace_win(dialog);
7602a3e3873SBaptiste Daroussin 	}
7612a3e3873SBaptiste Daroussin 
7624c8945a0SNathan Whitehorn 	if (state < 0) {
7634c8945a0SNathan Whitehorn 	    switch (state) {
7644c8945a0SNathan Whitehorn 	    case sTEXT:
7654c8945a0SNathan Whitehorn 		dlg_set_focus(dialog, w_text);
7664c8945a0SNathan Whitehorn 		break;
7674c8945a0SNathan Whitehorn 	    case sFILES:
7684c8945a0SNathan Whitehorn 		dlg_set_focus(dialog, f_list.win);
7694c8945a0SNathan Whitehorn 		break;
7704c8945a0SNathan Whitehorn 	    case sDIRS:
7714c8945a0SNathan Whitehorn 		dlg_set_focus(dialog, d_list.win);
7724c8945a0SNathan Whitehorn 		break;
7734c8945a0SNathan Whitehorn 	    }
7744c8945a0SNathan Whitehorn 	}
7754c8945a0SNathan Whitehorn 
7764c8945a0SNathan Whitehorn 	if (first) {
7774c8945a0SNathan Whitehorn 	    (void) wrefresh(dialog);
7784c8945a0SNathan Whitehorn 	} else {
7794c8945a0SNathan Whitehorn 	    fix_arrows(&d_list);
7804c8945a0SNathan Whitehorn 	    fix_arrows(&f_list);
7814c8945a0SNathan Whitehorn 	    key = dlg_mouse_wgetch((state == sTEXT) ? w_text : dialog, &fkey);
782*a96ef450SBaptiste Daroussin 	    if (dlg_result_key(key, fkey, &result)) {
783*a96ef450SBaptiste Daroussin 		if (!dlg_button_key(result, &button, &key, &fkey))
7844c8945a0SNathan Whitehorn 		    break;
7854c8945a0SNathan Whitehorn 	    }
786*a96ef450SBaptiste Daroussin 	}
7874c8945a0SNathan Whitehorn 
788f4f33ea0SBaptiste Daroussin 	if (key == DLGK_TOGGLE) {
7894c8945a0SNathan Whitehorn 	    key = DLGK_SELECT;
7904c8945a0SNathan Whitehorn 	    fkey = TRUE;
7914c8945a0SNathan Whitehorn 	}
7924c8945a0SNathan Whitehorn 
7934c8945a0SNathan Whitehorn 	if (fkey) {
7944c8945a0SNathan Whitehorn 	    switch (key) {
7954c8945a0SNathan Whitehorn 	    case DLGK_MOUSE(KEY_PREVIOUS):
7964c8945a0SNathan Whitehorn 		state = sDIRS;
7974c8945a0SNathan Whitehorn 		scroll_list(-1, which_list());
7984c8945a0SNathan Whitehorn 		continue;
7994c8945a0SNathan Whitehorn 	    case DLGK_MOUSE(KEY_NEXT):
8004c8945a0SNathan Whitehorn 		state = sDIRS;
8014c8945a0SNathan Whitehorn 		scroll_list(1, which_list());
8024c8945a0SNathan Whitehorn 		continue;
8034c8945a0SNathan Whitehorn 	    case DLGK_MOUSE(KEY_PPAGE):
8044c8945a0SNathan Whitehorn 		state = sFILES;
8054c8945a0SNathan Whitehorn 		scroll_list(-1, which_list());
8064c8945a0SNathan Whitehorn 		continue;
8074c8945a0SNathan Whitehorn 	    case DLGK_MOUSE(KEY_NPAGE):
8084c8945a0SNathan Whitehorn 		state = sFILES;
8094c8945a0SNathan Whitehorn 		scroll_list(1, which_list());
8104c8945a0SNathan Whitehorn 		continue;
8114c8945a0SNathan Whitehorn 	    case DLGK_PAGE_PREV:
8124c8945a0SNathan Whitehorn 		scroll_list(-1, which_list());
8134c8945a0SNathan Whitehorn 		continue;
8144c8945a0SNathan Whitehorn 	    case DLGK_PAGE_NEXT:
8154c8945a0SNathan Whitehorn 		scroll_list(1, which_list());
8164c8945a0SNathan Whitehorn 		continue;
8174c8945a0SNathan Whitehorn 	    case DLGK_ITEM_PREV:
8184c8945a0SNathan Whitehorn 		if (change_list(-1, which_list()))
8194c8945a0SNathan Whitehorn 		    continue;
8204c8945a0SNathan Whitehorn 		/* FALLTHRU */
8214c8945a0SNathan Whitehorn 	    case DLGK_FIELD_PREV:
8224c8945a0SNathan Whitehorn 		show_buttons = TRUE;
8234c8945a0SNathan Whitehorn 		do {
8244c8945a0SNathan Whitehorn 		    state = dlg_prev_ok_buttonindex(state, sDIRS);
8254c8945a0SNathan Whitehorn 		} while (!usable_state(state, &d_list, &f_list));
8264c8945a0SNathan Whitehorn 		continue;
8274c8945a0SNathan Whitehorn 	    case DLGK_ITEM_NEXT:
8284c8945a0SNathan Whitehorn 		if (change_list(1, which_list()))
8294c8945a0SNathan Whitehorn 		    continue;
8304c8945a0SNathan Whitehorn 		/* FALLTHRU */
8314c8945a0SNathan Whitehorn 	    case DLGK_FIELD_NEXT:
8324c8945a0SNathan Whitehorn 		show_buttons = TRUE;
8334c8945a0SNathan Whitehorn 		do {
8344c8945a0SNathan Whitehorn 		    state = dlg_next_ok_buttonindex(state, sDIRS);
8354c8945a0SNathan Whitehorn 		} while (!usable_state(state, &d_list, &f_list));
8364c8945a0SNathan Whitehorn 		continue;
8374c8945a0SNathan Whitehorn 	    case DLGK_SELECT:
8384c8945a0SNathan Whitehorn 		completed = 0;
8392a3e3873SBaptiste Daroussin 		if (partial != 0) {
8402a3e3873SBaptiste Daroussin 		    free(partial);
8414c8945a0SNathan Whitehorn 		    partial = 0;
8422a3e3873SBaptiste Daroussin 		}
8434c8945a0SNathan Whitehorn 		if (state == sFILES && !dselect) {
8444c8945a0SNathan Whitehorn 		    completed = data_of(&f_list);
8454c8945a0SNathan Whitehorn 		} else if (state == sDIRS) {
8464c8945a0SNathan Whitehorn 		    completed = data_of(&d_list);
8474c8945a0SNathan Whitehorn 		} else {
8484c8945a0SNathan Whitehorn 		    if (complete(input, &d_list, &f_list, &partial)) {
8494c8945a0SNathan Whitehorn 			completed = partial;
8504c8945a0SNathan Whitehorn 		    }
8514c8945a0SNathan Whitehorn 		}
8524c8945a0SNathan Whitehorn 		if (completed != 0) {
8534c8945a0SNathan Whitehorn 		    state = sTEXT;
8544c8945a0SNathan Whitehorn 		    show_buttons = TRUE;
8554c8945a0SNathan Whitehorn 		    strcpy(leaf_of(input), completed);
8564c8945a0SNathan Whitehorn 		    offset = (int) strlen(input);
8574c8945a0SNathan Whitehorn 		    dlg_show_string(w_text, input, offset, inputbox_attr,
8584c8945a0SNathan Whitehorn 				    0, 0, tbox_width, 0, first);
8592a3e3873SBaptiste Daroussin 		    if (partial != NULL) {
8604c8945a0SNathan Whitehorn 			free(partial);
8612a3e3873SBaptiste Daroussin 			partial = 0;
8622a3e3873SBaptiste Daroussin 		    }
8634c8945a0SNathan Whitehorn 		    continue;
8644c8945a0SNathan Whitehorn 		} else {	/* if (state < sTEXT) */
8654c8945a0SNathan Whitehorn 		    (void) beep();
8664c8945a0SNathan Whitehorn 		    continue;
8674c8945a0SNathan Whitehorn 		}
8684c8945a0SNathan Whitehorn 		/* FALLTHRU */
8694c8945a0SNathan Whitehorn 	    case DLGK_ENTER:
870682c9e0fSNathan Whitehorn 		result = (state > 0) ? dlg_enter_buttoncode(state) : DLG_EXIT_OK;
8714c8945a0SNathan Whitehorn 		continue;
872*a96ef450SBaptiste Daroussin 	    case DLGK_LEAVE:
873*a96ef450SBaptiste Daroussin 		if (state >= 0)
874*a96ef450SBaptiste Daroussin 		    result = dlg_ok_buttoncode(state);
875*a96ef450SBaptiste Daroussin 		break;
8764c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
8774c8945a0SNathan Whitehorn 	    case KEY_RESIZE:
878f4f33ea0SBaptiste Daroussin 		dlg_will_resize(dialog);
8794c8945a0SNathan Whitehorn 		/* reset data */
8804c8945a0SNathan Whitehorn 		height = old_height;
8814c8945a0SNathan Whitehorn 		width = old_width;
8824c8945a0SNathan Whitehorn 		show_buttons = TRUE;
8834c8945a0SNathan Whitehorn 		*current = 0;
8844c8945a0SNathan Whitehorn 		resized = TRUE;
8854c8945a0SNathan Whitehorn 		/* repaint */
886*a96ef450SBaptiste Daroussin 		free_list(&d_list, FALSE);
887*a96ef450SBaptiste Daroussin 		free_list(&f_list, FALSE);
888*a96ef450SBaptiste Daroussin 		_dlg_resize_cleanup(dialog);
8894c8945a0SNathan Whitehorn 		goto retry;
8904c8945a0SNathan Whitehorn #endif
8914c8945a0SNathan Whitehorn 	    default:
8924c8945a0SNathan Whitehorn 		if (key >= DLGK_MOUSE(MOUSE_T)) {
8934c8945a0SNathan Whitehorn 		    state = sTEXT;
8944c8945a0SNathan Whitehorn 		    continue;
8954c8945a0SNathan Whitehorn 		} else if (key >= DLGK_MOUSE(MOUSE_F)) {
8964c8945a0SNathan Whitehorn 		    if (f_list.win != 0) {
8974c8945a0SNathan Whitehorn 			state = sFILES;
8984c8945a0SNathan Whitehorn 			f_list.choice = (key - DLGK_MOUSE(MOUSE_F)) + f_list.offset;
8994c8945a0SNathan Whitehorn 			display_list(&f_list);
9004c8945a0SNathan Whitehorn 		    }
9014c8945a0SNathan Whitehorn 		    continue;
9024c8945a0SNathan Whitehorn 		} else if (key >= DLGK_MOUSE(MOUSE_D)) {
9034c8945a0SNathan Whitehorn 		    if (d_list.win != 0) {
9044c8945a0SNathan Whitehorn 			state = sDIRS;
9054c8945a0SNathan Whitehorn 			d_list.choice = (key - DLGK_MOUSE(MOUSE_D)) + d_list.offset;
9064c8945a0SNathan Whitehorn 			display_list(&d_list);
9074c8945a0SNathan Whitehorn 		    }
9084c8945a0SNathan Whitehorn 		    continue;
9094c8945a0SNathan Whitehorn 		} else if (is_DLGK_MOUSE(key)
9104c8945a0SNathan Whitehorn 			   && (code = dlg_ok_buttoncode(key - M_EVENT)) >= 0) {
9114c8945a0SNathan Whitehorn 		    result = code;
9124c8945a0SNathan Whitehorn 		    continue;
9134c8945a0SNathan Whitehorn 		}
9144c8945a0SNathan Whitehorn 		break;
9154c8945a0SNathan Whitehorn 	    }
9164c8945a0SNathan Whitehorn 	}
9174c8945a0SNathan Whitehorn 
9184c8945a0SNathan Whitehorn 	if (state < 0) {	/* Input box selected if we're editing */
9194c8945a0SNathan Whitehorn 	    int edit = dlg_edit_string(input, &offset, key, fkey, first);
9204c8945a0SNathan Whitehorn 
9214c8945a0SNathan Whitehorn 	    if (edit) {
9224c8945a0SNathan Whitehorn 		dlg_show_string(w_text, input, offset, inputbox_attr,
9234c8945a0SNathan Whitehorn 				0, 0, tbox_width, 0, first);
9244c8945a0SNathan Whitehorn 		first = FALSE;
9254c8945a0SNathan Whitehorn 		state = sTEXT;
9264c8945a0SNathan Whitehorn 	    }
927*a96ef450SBaptiste Daroussin 	} else if ((code = dlg_char_to_button(key, buttons)) >= 0) {
9284c8945a0SNathan Whitehorn 	    result = dlg_ok_buttoncode(code);
9294c8945a0SNathan Whitehorn 	    break;
9304c8945a0SNathan Whitehorn 	}
9314c8945a0SNathan Whitehorn     }
932*a96ef450SBaptiste Daroussin     AddLastKey();
9334c8945a0SNathan Whitehorn 
9344c8945a0SNathan Whitehorn     dlg_unregister_window(w_text);
9354c8945a0SNathan Whitehorn     dlg_del_window(dialog);
9364c8945a0SNathan Whitehorn     dlg_mouse_free_regions();
9374c8945a0SNathan Whitehorn     free_list(&d_list, FALSE);
9384c8945a0SNathan Whitehorn     free_list(&f_list, FALSE);
9392a3e3873SBaptiste Daroussin 
9402a3e3873SBaptiste Daroussin   finish:
9412a3e3873SBaptiste Daroussin     if (partial != 0)
9422a3e3873SBaptiste Daroussin 	free(partial);
9434c8945a0SNathan Whitehorn     return result;
9444c8945a0SNathan Whitehorn }
9454c8945a0SNathan Whitehorn 
9464c8945a0SNathan Whitehorn /*
9474c8945a0SNathan Whitehorn  * Display a dialog box for entering a filename
9484c8945a0SNathan Whitehorn  */
9494c8945a0SNathan Whitehorn int
dialog_fselect(const char * title,const char * path,int height,int width)9504c8945a0SNathan Whitehorn dialog_fselect(const char *title, const char *path, int height, int width)
9514c8945a0SNathan Whitehorn {
9524c8945a0SNathan Whitehorn     return dlg_fselect(title, path, height, width, FALSE);
9534c8945a0SNathan Whitehorn }
9544c8945a0SNathan Whitehorn 
9554c8945a0SNathan Whitehorn /*
9564c8945a0SNathan Whitehorn  * Display a dialog box for entering a directory
9574c8945a0SNathan Whitehorn  */
9584c8945a0SNathan Whitehorn int
dialog_dselect(const char * title,const char * path,int height,int width)9594c8945a0SNathan Whitehorn dialog_dselect(const char *title, const char *path, int height, int width)
9604c8945a0SNathan Whitehorn {
9614c8945a0SNathan Whitehorn     return dlg_fselect(title, path, height, width, TRUE);
9624c8945a0SNathan Whitehorn }
963