Merge from vendor branch CVS:
[dragonfly.git] / gnu / lib / libdialog / fselect.c
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
32 char *dialog_dfselect(char *dir, char *fmask, int is_fselect);
33
34 /*
35  * Functions
36  */
37
38 void
39 get_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
60 void
61 get_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
85 void
86 FreeNames(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
102 int
103 dialog_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
207 int
208 dialog_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
220 char *
221 dialog_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
229 char *
230 dialog_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