fselect.c revision 217309
1/*
2 * program:	fselect.c
3 * author:	Marc van Kempen (wmbfmk@urc.tue.nl)
4 * Desc:	File selection routine
5 *
6 * Copyright (c) 1995, Marc van Kempen
7 *
8 * All rights reserved.
9 *
10 * This software may be used, modified, copied, distributed, and
11 * sold, in both source and binary form provided that the above
12 * copyright and these terms are retained, verbatim, as the first
13 * lines of this file.  Under no circumstances is the author
14 * responsible for the proper functioning of this software, nor does
15 * the author assume any responsibility for damages incurred with
16 * its use.
17 *
18 */
19
20#include <stdlib.h>
21#include <unistd.h>
22#include <sys/param.h>
23#include <dialog.h>
24#include "ui_objects.h"
25#include "dir.h"
26#include "dialog.priv.h"
27
28/*
29 * Local prototypes
30 */
31
32char *dialog_dfselect(char *dir, char *fmask, int is_fselect);
33
34/*
35 * Functions
36 */
37
38void
39get_directories(DirList *d, int n, char ***names, int *nd)
40/*
41 * Desc: return the directorienames in <dir> as an array in
42 *	 <names>, the # of entries in <nd>, memory allocated
43 *       to *names should be freed when done with it.
44 */
45{
46    int i;
47
48    /* count the directories, which are in front */
49    *nd = 0;
50    while ((*nd < n) && (S_ISDIR(d[*nd].filestatus.st_mode))) (*nd)++;
51    *names = (char **) malloc( *nd * sizeof(char *) );
52    for (i=0; i<*nd; i++) {
53	(*names)[i] = (char *) malloc( strlen(d[i].filename) + 1);
54	strcpy((*names)[i], d[i].filename);
55    }
56
57    return;
58} /* get_directories() */
59
60void
61get_filenames(DirList *d, int n, char ***names, int *nf)
62/*
63 * Desc: return the filenames in <dir> as an arry in
64 *  	 <names>, the # of entries in <nf>, memory allocated
65 *	 to *names should be freed when done.
66 */
67{
68    int nd, i;
69
70    /* the # of regular files is the total # of files - # of directories */
71    /* count the # of directories */
72    nd = 0;
73    while ((nd < n) && (S_ISDIR(d[nd].filestatus.st_mode))) nd++;
74
75    *names = (char **) malloc( (n-nd) * sizeof(char *) );
76    *nf = n - nd;
77    for (i=0; i<*nf; i++) {
78	(*names)[i] = (char *) malloc( strlen(d[i+nd].filename) + 1);
79	strcpy((*names)[i], d[i+nd].filename);
80    }
81
82    return;
83} /* get_filenames() */
84
85void
86FreeNames(char **names, int n)
87/*
88 * Desc: free the space occupied by names
89 */
90{
91    int i;
92
93     /* free the space occupied by names */
94    for (i=0; i<n; i++) {
95	free(names[i]);
96    }
97    free(names);
98
99    return;
100} /* FreeNames() */
101
102int
103dialog_dselect_old(void)
104/*
105 * Desc: starting from the current directory,
106 *	 choose a new current directory
107 */
108{
109    DirList		*d = NULL;
110    char		**names, old_dir[MAXPATHLEN];
111    WINDOW		*ds_win;
112    ButtonObj		*okbut, *cancelbut;
113    ListObj		*dirs_obj;
114    StringObj		*dir_obj;
115    char		o_dir[MAXPATHLEN];
116    struct ComposeObj	*obj = NULL;
117    int			n, nd, okbutton, cancelbutton,
118			quit, cancel, ret;
119
120    ds_win = newwin(LINES-8, COLS-30, 4, 15);
121    if (ds_win == NULL) {
122	fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n",
123 		LINES-8, COLS-30, 4, 15);
124	exit(1);
125    }
126    draw_box(ds_win, 0, 0, LINES-8, COLS-30, dialog_attr, border_attr);
127    wattrset(ds_win, dialog_attr);
128    mvwaddstr(ds_win, 0, (COLS-30)/2 - 9, " Directory Select ");
129    draw_shadow(stdscr, 4, 15, LINES-8, COLS-30);
130    display_helpline(ds_win, LINES-9, COLS-30);
131
132    /* the Directory string input field */
133    getcwd(o_dir, MAXPATHLEN);
134    dir_obj = NewStringObj(ds_win, "Directory:", o_dir, 1, 2, COLS-34, MAXPATHLEN-1);
135    AddObj(&obj, STRINGOBJ, (void *) dir_obj);
136
137    /* the list of directories */
138    get_dir(".", "*", &d, &n);
139    get_directories(d, n, &names, &nd);
140    dirs_obj = NewListObj(ds_win, "Directories:", names, o_dir, 5, 2,
141			  LINES-15, COLS-48, nd);
142    AddObj(&obj, LISTOBJ, (void *) dirs_obj);
143
144    /* the Ok-button */
145    okbutton = FALSE;
146    okbut = NewButtonObj(ds_win, "Continue", &okbutton, 7, COLS-45);
147    AddObj(&obj, BUTTONOBJ, (void *) okbut);
148
149    /* the Cancel-button */
150    cancelbutton = FALSE;
151    cancelbut = NewButtonObj(ds_win, "Return", &cancelbutton, 11, COLS-44);
152    AddObj(&obj, BUTTONOBJ, (void *) cancelbut);
153
154    quit = FALSE;
155    cancel = FALSE;
156    strcpy(old_dir, o_dir);
157    while (!quit) {
158	ret = PollObj(&obj);
159	switch(ret) {
160	case SEL_BUTTON:
161	    if (okbutton) {
162		quit = TRUE;
163	    }
164	    if (cancelbutton) {
165		quit = TRUE;
166		cancel = TRUE;
167	    }
168	    break;
169	case SEL_CR:
170	    if (strcmp(old_dir, o_dir)) {
171		/* the directory was changed, cd into it */
172		if (chdir(o_dir)) {
173		    dialog_notify("Could not change into directory");
174		    strcpy(o_dir, old_dir);
175		} else {
176		    getcwd(o_dir, MAXPATHLEN);
177		    strcpy(old_dir, o_dir);
178		}
179		RefreshStringObj(dir_obj);
180	    }
181	    get_dir(".", "*", &d, &n);
182	    FreeNames(names, nd);
183	    get_directories(d, n, &names, &nd);
184	    UpdateListObj(dirs_obj, names, nd);
185	    if (((obj->prev)->obj == (void *) dirs_obj)) {
186		obj=obj->prev;
187	    }
188	    break;
189	case SEL_ESC:
190	    quit = TRUE;
191	    cancel = TRUE;
192	    break;
193	case KEY_F(1):
194	    display_helpfile();
195	    break;
196	}
197    }
198
199    FreeNames(names, nd);
200    DelObj(obj);
201    delwin(ds_win);
202
203    return(cancel);
204
205} /* dialog_dselect() */
206
207int
208dialog_dselect(char *dir, char *fmask)
209/*
210 * Desc: Choose a directory
211 */
212{
213    if (dialog_dfselect(dir, fmask, FALSE)) {
214	return(FALSE);	/* esc or cancel was pressed */
215    } else {
216	return(TRUE);   /* directory was selected */
217    }
218} /* dialog_dselect() */
219
220char *
221dialog_fselect(char *dir, char *fmask)
222/*
223 * Desc: Choose a file from a directory
224 */
225{
226    return(dialog_dfselect(dir, fmask, TRUE));
227} /* dialog_fselect() */
228
229char *
230dialog_dfselect(char *dir, char *fmask, int is_fselect)
231/*
232 * Desc: choose a file from the directory <dir>, which
233 *	 initially display files with the mask <filemask>
234 * pre:  <dir> is the initial directory
235 *	 only files corresponding to the mask <fmask> are displayed
236 * post: returns NULL if no file was selected
237 *       else returns pointer to filename, space is allocated, should
238 *       be freed after use.
239 */
240{
241    DirList 		*d = NULL;
242    char		msg[512];
243    char		**fnames, **dnames, *ret_name;
244    WINDOW		*fs_win;
245    int			n, nd, nf, ret;
246    StringObj		*fm_obj, *dir_obj, *sel_obj;
247    char		o_fm[255], o_dir[MAXPATHLEN], o_sel[MAXPATHLEN];
248    char		old_fmask[255], old_dir[MAXPATHLEN];
249    ListObj		*dirs_obj,   *files_obj;
250    struct ComposeObj	*obj = NULL, *o;
251    int 		quit, cancel;
252    ButtonObj		*okbut_obj, *canbut_obj;
253    int			ok_button, cancel_button;
254
255    if (chdir(dir)) {
256	sprintf(msg, "Could not move into specified directory: %s", dir);
257	dialog_notify(msg);
258	return(NULL);
259    }
260    getcwd(o_dir, MAXPATHLEN);
261
262    /* setup the fileselect-window and initialize its components */
263    fs_win = newwin(LINES-2, COLS-20, 1, 10);
264    if (fs_win == NULL) {
265	endwin();
266	fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n",
267		LINES-2, COLS-20, 2, 10);
268	exit(1);
269    }
270    draw_box(fs_win, 0, 0, LINES-2, COLS-20, dialog_attr, border_attr);
271    wattrset(fs_win, dialog_attr);
272    if (is_fselect) {
273	mvwaddstr(fs_win, 0, (COLS-20)/2 - 7, " File Select ");
274    } else {
275	mvwaddstr(fs_win, 0, (COLS-20)/2 - 9, " Directory Select ");
276    }
277    draw_shadow(stdscr, 1, 10, LINES-2, COLS-20);
278    display_helpline(fs_win, LINES-3, COLS-20);
279
280    /* Filemask entry */
281    strcpy(o_fm, fmask);
282    fm_obj = NewStringObj(fs_win, "Filemask:", o_fm, 1, 2, 19, 255);
283    AddObj(&obj, STRINGOBJ, (void *) fm_obj);
284
285    /* Directory entry */
286    dir_obj = NewStringObj(fs_win, "Directory:", o_dir, 1, 22, COLS-44, 255);
287    AddObj(&obj, STRINGOBJ, (void *) dir_obj);
288
289    /* Directory list */
290    get_dir(".", fmask, &d, &n);	/* read the entire directory */
291    get_directories(d, n, &dnames, &nd); /* extract the dir-entries */
292    if (is_fselect) {
293	dirs_obj = NewListObj(fs_win, "Directories:", dnames, o_dir, 5, 2,
294			      LINES-16, (COLS-20)/2-2, nd);
295    } else {
296	dirs_obj = NewListObj(fs_win, "Directories:", dnames, o_dir, 5, 2,
297			      LINES-12, (COLS-20)/2-2, nd);
298    }
299    AddObj(&obj, LISTOBJ, (void *) dirs_obj);
300
301    /* Filenames list */
302    get_filenames(d, n, &fnames, &nf);		/* extract the filenames */
303    if (is_fselect) {
304	files_obj = NewListObj(fs_win, "Files:", fnames, o_sel, 5, (COLS-20)/2+1,
305			       LINES-16, (COLS-20)/2-3, nf);
306    } else {
307	files_obj = NewListObj(fs_win, "Files:", fnames, o_sel, 5, (COLS-20)/2+1,
308			       LINES-12, (COLS-20)/2-3, nf);
309    }
310    AddObj(&obj, LISTOBJ, (void *) files_obj);
311
312    if (is_fselect) {
313	/* Selection entry */
314	o_sel[0] = '\0';
315	sel_obj = NewStringObj(fs_win, "Selection:", o_sel, LINES-10, 2, COLS-24, 255);
316	AddObj(&obj, STRINGOBJ, (void *) sel_obj);
317    }
318
319    /* Ok button */
320    ok_button = FALSE;
321    okbut_obj = NewButtonObj(fs_win, "Ok", &ok_button, LINES-6, 20);
322    AddObj(&obj, BUTTONOBJ, (void *) okbut_obj);
323
324    /* Cancel button */
325    cancel_button = FALSE;
326    canbut_obj = NewButtonObj(fs_win, "Cancel", &cancel_button, LINES-6, 30);
327    AddObj(&obj, BUTTONOBJ, (void *) canbut_obj);
328
329    /* Make sure all objects on the window are drawn */
330    wrefresh(fs_win);
331    keypad(fs_win, TRUE);
332
333    /* Start the reading */
334    o = obj;
335    strcpy(old_fmask, o_fm);
336    strcpy(old_dir, o_dir);
337    quit = FALSE;
338    cancel = FALSE;
339    while (!quit) {
340	ret = PollObj(&o);
341	switch(ret) {
342	case SEL_CR:
343	    if (strcmp(old_fmask, o_fm) || strcmp(old_dir, o_dir)) {
344		/* reread directory and update the listobjects */
345		if (strcmp(old_dir, o_dir)) { /* dir entry was changed */
346		    if (chdir(o_dir)) {
347			dialog_notify("Could not change into directory");
348			strcpy(o_dir, old_dir);
349		    } else {
350			getcwd(o_dir, MAXPATHLEN);
351			strcpy(old_dir, o_dir);
352		    }
353		    RefreshStringObj(dir_obj);
354		} else {		      /* fmask entry was changed */
355		    strcpy(old_fmask, o_fm);
356		}
357		get_dir(".", o_fm, &d, &n);
358		FreeNames(dnames, nd);
359		get_directories(d, n, &dnames, &nd);
360		UpdateListObj(dirs_obj, dnames, nd);
361		FreeNames(fnames, nf);
362		get_filenames(d, n, &fnames, &nf);
363		UpdateListObj(files_obj, fnames, nf);
364		if (((o->prev)->obj == (void *) dirs_obj)) {
365		    o=o->prev;
366		}
367	    }
368	    break;
369	case SEL_BUTTON:
370	    /* check which button was pressed */
371	    if (ok_button) {
372		quit = TRUE;
373	    }
374	    if (cancel_button) {
375		quit = TRUE;
376		cancel = TRUE;
377	    }
378	    break;
379	case SEL_ESC:
380	    quit = TRUE;
381	    cancel = TRUE;
382	    break;
383	case KEY_F(1):
384	case '?':
385	    display_helpfile();
386	    break;
387	}
388    }
389    DelObj(obj);
390    FreeNames(dnames, nd);
391    FreeNames(fnames, nf);
392    delwin(fs_win);
393
394    if (cancel || (strlen(o_sel) == 0)) {
395	return(NULL);
396    } else {
397	ret_name = (char *) malloc( strlen(o_sel) + 1 );
398	strcpy(ret_name, o_sel);
399	return(ret_name);
400    }
401} /* dialog_fselect() */
402
403