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