16458Sache/*
26458Sache * program:	fselect.c
36458Sache * author:	Marc van Kempen (wmbfmk@urc.tue.nl)
48858Srgrimes * Desc:	File selection routine
56458Sache *
66458Sache * Copyright (c) 1995, Marc van Kempen
76458Sache *
86458Sache * All rights reserved.
96458Sache *
106458Sache * This software may be used, modified, copied, distributed, and
116458Sache * sold, in both source and binary form provided that the above
126458Sache * copyright and these terms are retained, verbatim, as the first
136458Sache * lines of this file.  Under no circumstances is the author
146458Sache * responsible for the proper functioning of this software, nor does
156458Sache * the author assume any responsibility for damages incurred with
166458Sache * its use.
178858Srgrimes *
186458Sache */
196458Sache
206458Sache#include <stdlib.h>
216458Sache#include <unistd.h>
226458Sache#include <sys/param.h>
236458Sache#include <dialog.h>
246458Sache#include "ui_objects.h"
256458Sache#include "dir.h"
266458Sache#include "dialog.priv.h"
276458Sache
288548Sjkh/*
298548Sjkh * Local prototypes
308548Sjkh */
318548Sjkh
328548Sjkhchar *dialog_dfselect(char *dir, char *fmask, int is_fselect);
338548Sjkh
348858Srgrimes/*
358548Sjkh * Functions
368548Sjkh */
378548Sjkh
386458Sachevoid
396458Sacheget_directories(DirList *d, int n, char ***names, int *nd)
406458Sache/*
416458Sache * Desc: return the directorienames in <dir> as an array in
426458Sache *	 <names>, the # of entries in <nd>, memory allocated
436458Sache *       to *names should be freed when done with it.
446458Sache */
456458Sache{
466458Sache    int i;
476458Sache
486458Sache    /* count the directories, which are in front */
496458Sache    *nd = 0;
506458Sache    while ((*nd < n) && (S_ISDIR(d[*nd].filestatus.st_mode))) (*nd)++;
516458Sache    *names = (char **) malloc( *nd * sizeof(char *) );
526458Sache    for (i=0; i<*nd; i++) {
536458Sache	(*names)[i] = (char *) malloc( strlen(d[i].filename) + 1);
546458Sache	strcpy((*names)[i], d[i].filename);
556458Sache    }
566458Sache
576458Sache    return;
586458Sache} /* get_directories() */
596458Sache
606458Sachevoid
616458Sacheget_filenames(DirList *d, int n, char ***names, int *nf)
626458Sache/*
638858Srgrimes * Desc: return the filenames in <dir> as an arry in
646458Sache *  	 <names>, the # of entries in <nf>, memory allocated
656458Sache *	 to *names should be freed when done.
666458Sache */
676458Sache{
686458Sache    int nd, i;
696458Sache
706458Sache    /* the # of regular files is the total # of files - # of directories */
716458Sache    /* count the # of directories */
726458Sache    nd = 0;
736458Sache    while ((nd < n) && (S_ISDIR(d[nd].filestatus.st_mode))) nd++;
746458Sache
756458Sache    *names = (char **) malloc( (n-nd) * sizeof(char *) );
766458Sache    *nf = n - nd;
776458Sache    for (i=0; i<*nf; i++) {
786458Sache	(*names)[i] = (char *) malloc( strlen(d[i+nd].filename) + 1);
796458Sache	strcpy((*names)[i], d[i+nd].filename);
806458Sache    }
818858Srgrimes
826458Sache    return;
836458Sache} /* get_filenames() */
846458Sache
856458Sachevoid
866458SacheFreeNames(char **names, int n)
876458Sache/*
886458Sache * Desc: free the space occupied by names
896458Sache */
906458Sache{
916458Sache    int i;
926458Sache
936458Sache     /* free the space occupied by names */
946458Sache    for (i=0; i<n; i++) {
956458Sache	free(names[i]);
966458Sache    }
976458Sache    free(names);
986458Sache
996458Sache    return;
1006458Sache} /* FreeNames() */
1016458Sache
1027959Sacheint
1038548Sjkhdialog_dselect_old(void)
1047959Sache/*
1058858Srgrimes * Desc: starting from the current directory,
1068858Srgrimes *	 choose a new current directory
1077959Sache */
1087959Sache{
1097959Sache    DirList		*d = NULL;
1107959Sache    char		**names, old_dir[MAXPATHLEN];
1117959Sache    WINDOW		*ds_win;
1127959Sache    ButtonObj		*okbut, *cancelbut;
1137959Sache    ListObj		*dirs_obj;
1147959Sache    StringObj		*dir_obj;
1157959Sache    char		o_dir[MAXPATHLEN];
1167959Sache    struct ComposeObj	*obj = NULL;
1178858Srgrimes    int			n, nd, okbutton, cancelbutton,
1187959Sache			quit, cancel, ret;
1197959Sache
1207959Sache    ds_win = newwin(LINES-8, COLS-30, 4, 15);
1217959Sache    if (ds_win == NULL) {
1228858Srgrimes	fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n",
1237959Sache 		LINES-8, COLS-30, 4, 15);
1247959Sache	exit(1);
1257959Sache    }
1267959Sache    draw_box(ds_win, 0, 0, LINES-8, COLS-30, dialog_attr, border_attr);
1277959Sache    wattrset(ds_win, dialog_attr);
1287959Sache    mvwaddstr(ds_win, 0, (COLS-30)/2 - 9, " Directory Select ");
1297959Sache    draw_shadow(stdscr, 4, 15, LINES-8, COLS-30);
1307959Sache    display_helpline(ds_win, LINES-9, COLS-30);
1317959Sache
1327959Sache    /* the Directory string input field */
1337959Sache    getcwd(o_dir, MAXPATHLEN);
1347959Sache    dir_obj = NewStringObj(ds_win, "Directory:", o_dir, 1, 2, COLS-34, MAXPATHLEN-1);
1357959Sache    AddObj(&obj, STRINGOBJ, (void *) dir_obj);
1367959Sache
1377959Sache    /* the list of directories */
1387959Sache    get_dir(".", "*", &d, &n);
1397959Sache    get_directories(d, n, &names, &nd);
1408858Srgrimes    dirs_obj = NewListObj(ds_win, "Directories:", names, o_dir, 5, 2,
1417959Sache			  LINES-15, COLS-48, nd);
1427959Sache    AddObj(&obj, LISTOBJ, (void *) dirs_obj);
1437959Sache
1447959Sache    /* the Ok-button */
1457959Sache    okbutton = FALSE;
1468548Sjkh    okbut = NewButtonObj(ds_win, "Continue", &okbutton, 7, COLS-45);
1477959Sache    AddObj(&obj, BUTTONOBJ, (void *) okbut);
1488858Srgrimes
1497959Sache    /* the Cancel-button */
1507959Sache    cancelbutton = FALSE;
1518548Sjkh    cancelbut = NewButtonObj(ds_win, "Return", &cancelbutton, 11, COLS-44);
1527959Sache    AddObj(&obj, BUTTONOBJ, (void *) cancelbut);
1537959Sache
1547959Sache    quit = FALSE;
1557959Sache    cancel = FALSE;
1567959Sache    strcpy(old_dir, o_dir);
1577959Sache    while (!quit) {
1587959Sache	ret = PollObj(&obj);
1597959Sache	switch(ret) {
1607959Sache	case SEL_BUTTON:
1617959Sache	    if (okbutton) {
1627959Sache		quit = TRUE;
1637959Sache	    }
1647959Sache	    if (cancelbutton) {
1657959Sache		quit = TRUE;
1667959Sache		cancel = TRUE;
1677959Sache	    }
1687959Sache	    break;
1697959Sache	case SEL_CR:
1707959Sache	    if (strcmp(old_dir, o_dir)) {
1717959Sache		/* the directory was changed, cd into it */
1727959Sache		if (chdir(o_dir)) {
1737959Sache		    dialog_notify("Could not change into directory");
17422879Sache		    strcpy(o_dir, old_dir);
1757959Sache		} else {
1767959Sache		    getcwd(o_dir, MAXPATHLEN);
1777959Sache		    strcpy(old_dir, o_dir);
1787959Sache		}
17922879Sache		RefreshStringObj(dir_obj);
1808858Srgrimes	    }
1817959Sache	    get_dir(".", "*", &d, &n);
1827959Sache	    FreeNames(names, nd);
1837959Sache	    get_directories(d, n, &names, &nd);
1847959Sache	    UpdateListObj(dirs_obj, names, nd);
1857959Sache	    if (((obj->prev)->obj == (void *) dirs_obj)) {
1867959Sache		obj=obj->prev;
1877959Sache	    }
1887959Sache	    break;
1897959Sache	case SEL_ESC:
1907959Sache	    quit = TRUE;
1917959Sache	    cancel = TRUE;
1927959Sache	    break;
1937959Sache	case KEY_F(1):
1947959Sache	    display_helpfile();
1957959Sache	    break;
1967959Sache	}
1977959Sache    }
1988858Srgrimes
1997959Sache    FreeNames(names, nd);
2007959Sache    DelObj(obj);
2017959Sache    delwin(ds_win);
2027959Sache
2037959Sache    return(cancel);
2047959Sache
2057959Sache} /* dialog_dselect() */
2067959Sache
2078548Sjkhint
2088548Sjkhdialog_dselect(char *dir, char *fmask)
2098548Sjkh/*
2108548Sjkh * Desc: Choose a directory
2118548Sjkh */
2128548Sjkh{
2138548Sjkh    if (dialog_dfselect(dir, fmask, FALSE)) {
2148548Sjkh	return(FALSE);	/* esc or cancel was pressed */
2158548Sjkh    } else {
2168548Sjkh	return(TRUE);   /* directory was selected */
2178548Sjkh    }
2188548Sjkh} /* dialog_dselect() */
2198548Sjkh
2206458Sachechar *
2216458Sachedialog_fselect(char *dir, char *fmask)
2226458Sache/*
2238548Sjkh * Desc: Choose a file from a directory
2248548Sjkh */
2258548Sjkh{
2268548Sjkh    return(dialog_dfselect(dir, fmask, TRUE));
2278548Sjkh} /* dialog_fselect() */
2288548Sjkh
2298548Sjkhchar *
2308548Sjkhdialog_dfselect(char *dir, char *fmask, int is_fselect)
2318548Sjkh/*
2326458Sache * Desc: choose a file from the directory <dir>, which
2338858Srgrimes *	 initially display files with the mask <filemask>
2346458Sache * pre:  <dir> is the initial directory
2356458Sache *	 only files corresponding to the mask <fmask> are displayed
2366458Sache * post: returns NULL if no file was selected
2376458Sache *       else returns pointer to filename, space is allocated, should
2386458Sache *       be freed after use.
2396458Sache */
2406458Sache{
2416458Sache    DirList 		*d = NULL;
2426458Sache    char		msg[512];
2437959Sache    char		**fnames, **dnames, *ret_name;
2446458Sache    WINDOW		*fs_win;
2456458Sache    int			n, nd, nf, ret;
2466458Sache    StringObj		*fm_obj, *dir_obj, *sel_obj;
2476458Sache    char		o_fm[255], o_dir[MAXPATHLEN], o_sel[MAXPATHLEN];
2486458Sache    char		old_fmask[255], old_dir[MAXPATHLEN];
2496458Sache    ListObj		*dirs_obj,   *files_obj;
2506458Sache    struct ComposeObj	*obj = NULL, *o;
2516458Sache    int 		quit, cancel;
2526458Sache    ButtonObj		*okbut_obj, *canbut_obj;
2536458Sache    int			ok_button, cancel_button;
2546458Sache
2556458Sache    if (chdir(dir)) {
2566458Sache	sprintf(msg, "Could not move into specified directory: %s", dir);
2576458Sache	dialog_notify(msg);
2586458Sache	return(NULL);
2596458Sache    }
2606458Sache    getcwd(o_dir, MAXPATHLEN);
2616458Sache
2626458Sache    /* setup the fileselect-window and initialize its components */
2636458Sache    fs_win = newwin(LINES-2, COLS-20, 1, 10);
2646458Sache    if (fs_win == NULL) {
2656458Sache	endwin();
2668858Srgrimes	fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n",
2676458Sache		LINES-2, COLS-20, 2, 10);
2686458Sache	exit(1);
2696458Sache    }
2706458Sache    draw_box(fs_win, 0, 0, LINES-2, COLS-20, dialog_attr, border_attr);
2716458Sache    wattrset(fs_win, dialog_attr);
2728548Sjkh    if (is_fselect) {
2738548Sjkh	mvwaddstr(fs_win, 0, (COLS-20)/2 - 7, " File Select ");
2748548Sjkh    } else {
2758548Sjkh	mvwaddstr(fs_win, 0, (COLS-20)/2 - 9, " Directory Select ");
2768548Sjkh    }
2776458Sache    draw_shadow(stdscr, 1, 10, LINES-2, COLS-20);
2788548Sjkh    display_helpline(fs_win, LINES-3, COLS-20);
2796458Sache
2806458Sache    /* Filemask entry */
2816458Sache    strcpy(o_fm, fmask);
2826458Sache    fm_obj = NewStringObj(fs_win, "Filemask:", o_fm, 1, 2, 19, 255);
2836458Sache    AddObj(&obj, STRINGOBJ, (void *) fm_obj);
2846458Sache
2856458Sache    /* Directory entry */
2866458Sache    dir_obj = NewStringObj(fs_win, "Directory:", o_dir, 1, 22, COLS-44, 255);
2876458Sache    AddObj(&obj, STRINGOBJ, (void *) dir_obj);
2886458Sache
2896458Sache    /* Directory list */
2906458Sache    get_dir(".", fmask, &d, &n);	/* read the entire directory */
2917959Sache    get_directories(d, n, &dnames, &nd); /* extract the dir-entries */
2928548Sjkh    if (is_fselect) {
2938858Srgrimes	dirs_obj = NewListObj(fs_win, "Directories:", dnames, o_dir, 5, 2,
2948548Sjkh			      LINES-16, (COLS-20)/2-2, nd);
2958548Sjkh    } else {
2968548Sjkh	dirs_obj = NewListObj(fs_win, "Directories:", dnames, o_dir, 5, 2,
2978548Sjkh			      LINES-12, (COLS-20)/2-2, nd);
2988548Sjkh    }
2996458Sache    AddObj(&obj, LISTOBJ, (void *) dirs_obj);
3006458Sache
3016458Sache    /* Filenames list */
3027959Sache    get_filenames(d, n, &fnames, &nf);		/* extract the filenames */
3038548Sjkh    if (is_fselect) {
3048548Sjkh	files_obj = NewListObj(fs_win, "Files:", fnames, o_sel, 5, (COLS-20)/2+1,
3058548Sjkh			       LINES-16, (COLS-20)/2-3, nf);
3068548Sjkh    } else {
3078548Sjkh	files_obj = NewListObj(fs_win, "Files:", fnames, o_sel, 5, (COLS-20)/2+1,
3088548Sjkh			       LINES-12, (COLS-20)/2-3, nf);
3098548Sjkh    }
3106458Sache    AddObj(&obj, LISTOBJ, (void *) files_obj);
3116458Sache
3128548Sjkh    if (is_fselect) {
3138548Sjkh	/* Selection entry */
3148548Sjkh	o_sel[0] = '\0';
3158548Sjkh	sel_obj = NewStringObj(fs_win, "Selection:", o_sel, LINES-10, 2, COLS-24, 255);
3168548Sjkh	AddObj(&obj, STRINGOBJ, (void *) sel_obj);
3178548Sjkh    }
3186458Sache
3196458Sache    /* Ok button */
3206458Sache    ok_button = FALSE;
3216458Sache    okbut_obj = NewButtonObj(fs_win, "Ok", &ok_button, LINES-6, 20);
3226458Sache    AddObj(&obj, BUTTONOBJ, (void *) okbut_obj);
3236458Sache
3246458Sache    /* Cancel button */
3256458Sache    cancel_button = FALSE;
3266458Sache    canbut_obj = NewButtonObj(fs_win, "Cancel", &cancel_button, LINES-6, 30);
3276458Sache    AddObj(&obj, BUTTONOBJ, (void *) canbut_obj);
3286458Sache
3296458Sache    /* Make sure all objects on the window are drawn */
3306458Sache    wrefresh(fs_win);
3316458Sache    keypad(fs_win, TRUE);
3326458Sache
3336458Sache    /* Start the reading */
3346458Sache    o = obj;
3356458Sache    strcpy(old_fmask, o_fm);
3366458Sache    strcpy(old_dir, o_dir);
3376458Sache    quit = FALSE;
3386458Sache    cancel = FALSE;
3396458Sache    while (!quit) {
3406458Sache	ret = PollObj(&o);
3416458Sache	switch(ret) {
3426458Sache	case SEL_CR:
3436458Sache	    if (strcmp(old_fmask, o_fm) || strcmp(old_dir, o_dir)) {
3448858Srgrimes		/* reread directory and update the listobjects */
3456458Sache		if (strcmp(old_dir, o_dir)) { /* dir entry was changed */
3466458Sache		    if (chdir(o_dir)) {
3476458Sache			dialog_notify("Could not change into directory");
34822879Sache			strcpy(o_dir, old_dir);
3496458Sache		    } else {
3506458Sache			getcwd(o_dir, MAXPATHLEN);
3516458Sache			strcpy(old_dir, o_dir);
3526458Sache		    }
35322879Sache		    RefreshStringObj(dir_obj);
3546458Sache		} else {		      /* fmask entry was changed */
3556458Sache		    strcpy(old_fmask, o_fm);
3566458Sache		}
3576458Sache		get_dir(".", o_fm, &d, &n);
3587959Sache		FreeNames(dnames, nd);
3597959Sache		get_directories(d, n, &dnames, &nd);
3607959Sache		UpdateListObj(dirs_obj, dnames, nd);
3617959Sache		FreeNames(fnames, nf);
3627959Sache		get_filenames(d, n, &fnames, &nf);
3637959Sache		UpdateListObj(files_obj, fnames, nf);
3646458Sache		if (((o->prev)->obj == (void *) dirs_obj)) {
3656458Sache		    o=o->prev;
3666458Sache		}
3676458Sache	    }
3686458Sache	    break;
3696458Sache	case SEL_BUTTON:
3706458Sache	    /* check which button was pressed */
3716458Sache	    if (ok_button) {
3726458Sache		quit = TRUE;
3736458Sache	    }
3746458Sache	    if (cancel_button) {
3756458Sache		quit = TRUE;
3766458Sache		cancel = TRUE;
3776458Sache	    }
3786458Sache	    break;
3796458Sache	case SEL_ESC:
3806458Sache	    quit = TRUE;
3816458Sache	    cancel = TRUE;
3826458Sache	    break;
3836458Sache	case KEY_F(1):
3846458Sache	case '?':
3856458Sache	    display_helpfile();
3866458Sache	    break;
3876458Sache	}
3886458Sache    }
3896458Sache    DelObj(obj);
3907959Sache    FreeNames(dnames, nd);
3917959Sache    FreeNames(fnames, nf);
3927959Sache    delwin(fs_win);
3936458Sache
3946458Sache    if (cancel || (strlen(o_sel) == 0)) {
3956458Sache	return(NULL);
3966458Sache    } else {
3976458Sache	ret_name = (char *) malloc( strlen(o_sel) + 1 );
3986458Sache	strcpy(ret_name, o_sel);
3996458Sache	return(ret_name);
4006458Sache    }
4016458Sache} /* dialog_fselect() */
4026458Sache
403