1 /* filesel.c: File selection dialog box
2 Copyright (c) 2001-2015 Matan Ziv-Av, Philip Kendall, Russell Marks,
3 Marek Januszewski
4 Copyright (c) 2015 Sergio Baldoví
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 Author contact information:
21
22 E-mail: philip-fuse@shadowmagic.org.uk
23
24 */
25
26 #include <config.h>
27
28 #include <sys/types.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #ifdef HAVE_STRINGS_STRCASECMP
34 #include <strings.h>
35 #endif /* #ifdef HAVE_STRINGS_STRCASECMP */
36 #include <sys/stat.h>
37 #include <unistd.h>
38
39 #ifdef WIN32
40 #include <windows.h>
41 #include <direct.h>
42 #include <ctype.h>
43 #endif /* #ifdef WIN32 */
44
45 #include "fuse.h"
46 #include "ui/ui.h"
47 #include "utils.h"
48 #include "widget_internals.h"
49
50 #if defined AMIGA || defined __MORPHOS__
51 #include <proto/asl.h>
52 #include <proto/dos.h>
53 #include <proto/exec.h>
54
55 struct Library *AslBase;
56
57 #ifndef __MORPHOS__
58 struct AslIFace *IAsl;
59 struct Library *DOSBase;
60 #endif /* #ifndef __MORPHOS__ */
61
62 #ifndef __MORPHOS__
63 struct DOSIFace *IDOS;
64 struct Library *ExecBase;
65 #endif /* #ifndef __MORPHOS__ */
66
67
68 int err = 0;
69
70 char *amiga_asl( char *title, BOOL is_saving );
71
72 #endif /* ifdef AMIGA */
73
74 struct widget_dirent **widget_filenames; /* Filenames in the current
75 directory */
76 size_t widget_numfiles; /* The number of files in the current
77 directory */
78
79 static const char *title;
80 static int is_saving;
81
82 #ifdef WIN32
83 static int is_drivesel = 0;
84 static int is_rootdir;
85 #endif /* #ifdef WIN32 */
86
87 #define ENTRIES_PER_SCREEN (is_saving ? 32 : 36)
88
89 /* The number of the filename in the top-left corner of the current
90 display, that of the filename which the `cursor' is on, and that
91 which it will be on after this keypress */
92 static size_t top_left_file, current_file, new_current_file;
93
94 static char *widget_get_filename( const char *title, int saving );
95
96 static int widget_add_filename( int *allocated, int *number,
97 struct widget_dirent ***namelist,
98 const char *name );
99 static void widget_scan( char *dir );
100 static int widget_select_file( const char *name );
101 static int widget_scan_compare( const widget_dirent **a,
102 const widget_dirent **b );
103
104 #if !defined AMIGA && !defined __MORPHOS__
105 static char* widget_getcwd( void );
106 #endif /* ifndef AMIGA */
107 static int widget_print_all_filenames( struct widget_dirent **filenames, int n,
108 int top_left, int current,
109 const char *dir );
110 static int widget_print_filename( struct widget_dirent *filename, int position,
111 int inverted );
112 #ifdef WIN32
113 static void widget_filesel_chdrv( void );
114 static void widget_filesel_drvlist( void );
115 #endif /* #ifdef WIN32 */
116 static int widget_filesel_chdir( void );
117
118 /* The filename to return */
119 char* widget_filesel_name;
120
121 /* Should we exit all widgets when we're done with this selector? */
122 static int exit_all_widgets;
123
124 static char *
widget_get_filename(const char * title,int saving)125 widget_get_filename( const char *title, int saving )
126 {
127 char *filename = NULL;
128
129 widget_filesel_data data;
130
131 data.exit_all_widgets = 1;
132 data.title = title;
133
134 if( saving ) {
135 widget_do_fileselector_save( &data );
136 } else {
137 widget_do_fileselector( &data );
138 }
139 if( widget_filesel_name )
140 filename = utils_safe_strdup( widget_filesel_name );
141
142 return filename;
143
144 }
145
146 char *
ui_get_open_filename(const char * title)147 ui_get_open_filename( const char *title )
148 {
149 #if !defined AMIGA && !defined __MORPHOS__
150 return widget_get_filename( title, 0 );
151 #else
152 return amiga_asl( title, FALSE );
153 #endif
154 }
155
156 char *
ui_get_save_filename(const char * title)157 ui_get_save_filename( const char *title )
158 {
159 #if !defined AMIGA && !defined __MORPHOS__
160 return widget_get_filename( title, 1 );
161 #else
162 return amiga_asl( title, TRUE );
163 #endif
164 }
165
widget_add_filename(int * allocated,int * number,struct widget_dirent *** namelist,const char * name)166 static int widget_add_filename( int *allocated, int *number,
167 struct widget_dirent ***namelist,
168 const char *name ) {
169 int i; size_t length;
170
171 if( ++*number > *allocated ) {
172 struct widget_dirent **oldptr = *namelist;
173
174 *namelist = realloc( (*namelist), 2 * *allocated * sizeof(**namelist) );
175 if( *namelist == NULL ) {
176 for( i=0; i<*number-1; i++ ) {
177 free( oldptr[i]->name );
178 free( oldptr[i] );
179 }
180 free( oldptr );
181 return -1;
182 }
183 *allocated *= 2;
184 }
185
186 (*namelist)[*number-1] = malloc( sizeof(***namelist) );
187 if( !(*namelist)[*number-1] ) {
188 for( i=0; i<*number-1; i++ ) {
189 free( (*namelist)[i]->name );
190 free( (*namelist)[i] );
191 }
192 free( *namelist );
193 *namelist = NULL;
194 return -1;
195 }
196
197 length = strlen( name ) + 1;
198 if( length < 16 ) length = 16;
199
200 (*namelist)[*number-1]->name = malloc( length );
201 if( !(*namelist)[*number-1]->name ) {
202 free( (*namelist)[*number-1] );
203 for( i=0; i<*number-1; i++ ) {
204 free( (*namelist)[i]->name );
205 free( (*namelist)[i] );
206 }
207 free( *namelist );
208 *namelist = NULL;
209 return -1;
210 }
211
212 strncpy( (*namelist)[*number-1]->name, name, length );
213 (*namelist)[*number-1]->name[ length - 1 ] = 0;
214
215 return 0;
216 }
217
218 #if defined AMIGA || defined __MORPHOS__
219 char *
amiga_asl(char * title,BOOL is_saving)220 amiga_asl( char *title, BOOL is_saving ) {
221 char *filename;
222 struct FileRequester *filereq;
223
224 #ifndef __MORPHOS__
225 if( AslBase = IExec->OpenLibrary( "asl.library", 52 ) ) {
226 if( IAsl = ( struct AslIFace * ) IExec->GetInterface( AslBase,"main",1,NULL ) ) {
227 filereq = IAsl->AllocAslRequestTags( ASL_FileRequest,
228 ASLFR_RejectIcons,TRUE,
229 ASLFR_TitleText,title,
230 ASLFR_DoSaveMode,is_saving,
231 ASLFR_InitialPattern,"#?.(sna|z80|szx|sp|snp|zxs|tap|tzx|csw|rzx|dsk|trd|scl|mdr|dck|hdf|rom|psg|scr|mlt|png|gz|bz2)",
232 ASLFR_DoPatterns,TRUE,
233 TAG_DONE );
234 if( err = IAsl->AslRequest( filereq, NULL ) ) {
235 filename = ( STRPTR ) IExec->AllocVec( 1024, MEMF_CLEAR );
236 #else /* #ifndef __MORPHOS__ */
237 if( AslBase = OpenLibrary( "asl.library", 0 ) ) {
238 filereq = AllocAslRequestTags( ASL_FileRequest,
239 ASLFR_RejectIcons,TRUE,
240 ASLFR_TitleText,title,
241 ASLFR_DoSaveMode,is_saving,
242 ASLFR_InitialPattern,"#?.(sna|z80|szx|sp|snp|zxs|tap|tzx|csw|rzx|dsk|trd|scl|mdr|dck|hdf|rom|psg|scr|mlt|png|gz|bz2)",
243 ASLFR_DoPatterns,TRUE,
244 TAG_DONE );
245 if( err = AslRequest( filereq, NULL ) ) {
246 filename = ( STRPTR ) AllocVec( 1024, MEMF_CLEAR );
247 #endif /* #ifndef __MORPHOS__ */
248
249 strcpy( filename,filereq->fr_Drawer );
250 #ifndef __MORPHOS__
251 IDOS->AddPart( filename, filereq->fr_File, 1024 );
252 #else /* #ifndef __MORPHOS__ */
253 AddPart( filename, filereq->fr_File, 1024 );
254 #endif /* #ifndef __MORPHOS__ */
255 widget_filesel_name = utils_safe_strdup( filename );
256 #ifndef __MORPHOS__
257 IExec->FreeVec( filename );
258 #else /* #ifndef __MORPHOS__ */
259 FreeVec( filename );
260 #endif /* #ifndef __MORPHOS__ */
261 err = WIDGET_FINISHED_OK;
262 } else {
263 err = WIDGET_FINISHED_CANCEL;
264 }
265 #ifndef __MORPHOS__
266 IExec->DropInterface( ( struct Interface * )IAsl );
267 }
268 IExec->CloseLibrary( AslBase );
269 #else /* #ifndef __MORPHOS__ */
270 CloseLibrary( AslBase );
271 #endif /* #ifndef __MORPHOS__ */
272 }
273 return widget_filesel_name;
274 }
275 #else /* ifdef AMIGA */
276
277 static int widget_scandir( const char *dir, struct widget_dirent ***namelist,
278 int (*select_fn)(const char*) )
279 {
280 compat_dir directory;
281
282 int allocated, number;
283 int i;
284 int done = 0;
285
286 *namelist = malloc( 32 * sizeof(**namelist) );
287 if( !*namelist ) return -1;
288
289 allocated = 32; number = 0;
290
291 directory = compat_opendir( dir );
292 if( !directory ) {
293 free( *namelist );
294 *namelist = NULL;
295 return -1;
296 }
297
298 #ifdef WIN32
299 /* Assume this is the root directory, unless we find an entry named ".." */
300 is_rootdir = 1;
301 #endif /* #ifdef WIN32 */
302
303 while( !done ) {
304 char name[ PATH_MAX ];
305
306 compat_dir_result_t result =
307 compat_readdir( directory, name, sizeof( name ) );
308
309 switch( result )
310 {
311 case COMPAT_DIR_RESULT_OK:
312 if( select_fn( name ) ) {
313 #ifdef WIN32
314 if( is_rootdir && !strcmp( name, ".." ) ) {
315 is_rootdir = 0;
316 }
317 #endif /* #ifdef WIN32 */
318 if( widget_add_filename( &allocated, &number, namelist, name ) ) {
319 compat_closedir( directory );
320 return -1;
321 }
322 }
323 break;
324
325 case COMPAT_DIR_RESULT_END:
326 done = 1;
327 break;
328
329 case COMPAT_DIR_RESULT_ERROR:
330 for( i=0; i<number; i++ ) {
331 free( (*namelist)[i]->name );
332 free( (*namelist)[i] );
333 }
334 free( *namelist );
335 *namelist = NULL;
336 compat_closedir( directory );
337 return -1;
338 }
339
340 }
341
342 if( compat_closedir( directory ) ) {
343 for( i=0; i<number; i++ ) {
344 free( (*namelist)[i]->name );
345 free( (*namelist)[i] );
346 }
347 free( *namelist );
348 *namelist = NULL;
349 return -1;
350 }
351
352 #ifdef WIN32
353 if( is_rootdir ) {
354 /* Add a fake ".." entry for drive selection */
355 if( widget_add_filename( &allocated, &number, namelist, ".." ) ) {
356 return -1;
357 }
358 }
359 #endif /* #ifdef WIN32 */
360
361 return number;
362 }
363
364 #ifdef WIN32
365 static int widget_scandrives( struct widget_dirent ***namelist )
366 {
367 int allocated, number;
368 unsigned long drivemask;
369 int i;
370 char drive[3];
371 const char *driveletters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
372
373 drive[1] = ':';
374 drive[2] = '\0';
375
376 *namelist = malloc( 32 * sizeof(**namelist) );
377 if( !*namelist ) return -1;
378
379 allocated = 32; number = 0;
380
381 drivemask = _getdrives();
382 if( !drivemask ) {
383 free( *namelist );
384 *namelist = NULL;
385 return -1;
386 }
387
388 for( i = 0; i < 26; i++ ) {
389 if( drivemask & 1) {
390 drive[0] = driveletters[i];
391 if( widget_add_filename( &allocated, &number, namelist, drive ) ) {
392 return -1;
393 }
394 }
395 drivemask >>= 1;
396 }
397
398 return number;
399 }
400 #endif
401
402 static void widget_scan( char *dir )
403 {
404 struct stat file_info;
405
406 size_t i; int error;
407
408 /* Free the memory belonging to the files in the previous directory */
409 for( i=0; i<widget_numfiles; i++ ) {
410 free( widget_filenames[i]->name );
411 free( widget_filenames[i] );
412 }
413
414 #ifdef WIN32
415 if( dir ) {
416 widget_numfiles = widget_scandir( dir, &widget_filenames,
417 widget_select_file );
418 } else {
419 widget_numfiles = widget_scandrives( &widget_filenames );
420 }
421 #else /* #ifdef WIN32 */
422 widget_numfiles = widget_scandir( dir, &widget_filenames,
423 widget_select_file );
424 #endif /* #ifdef WIN32 */
425
426 if( widget_numfiles == (size_t)-1 ) return;
427
428 for( i=0; i<widget_numfiles; i++ ) {
429 error = stat( widget_filenames[i]->name, &file_info );
430 widget_filenames[i]->mode = error ? 0 : file_info.st_mode;
431 }
432
433 qsort( widget_filenames, widget_numfiles, sizeof(struct widget_dirent*),
434 (int(*)(const void*,const void*))widget_scan_compare );
435
436 }
437
438 static int
439 widget_select_file( const char *name )
440 {
441 if( !name ) return 0;
442
443 /* Skip current directory */
444 if( !strcmp( name, "." ) ) return 0;
445
446 #ifndef WIN32
447 /* Skip hidden files/directories */
448 if( strlen( name ) > 1 && name[0] == '.' && name[1] != '.' ) return 0;
449 #endif /* #ifdef WIN32 */
450
451 return 1;
452 }
453
454 static int widget_scan_compare( const struct widget_dirent **a,
455 const struct widget_dirent **b )
456 {
457 int isdir1 = S_ISDIR( (*a)->mode ),
458 isdir2 = S_ISDIR( (*b)->mode );
459
460 if( isdir1 && !isdir2 ) {
461 return -1;
462 } else if( isdir2 && !isdir1 ) {
463 return 1;
464 } else {
465 return strcmp( (*a)->name, (*b)->name );
466 }
467
468 }
469 #endif /* ifdef AMIGA */
470
471 /* File selection widget */
472
473 static int
474 widget_filesel_draw( void *data )
475 {
476 widget_filesel_data *filesel_data = data;
477 char *directory;
478 int error;
479
480 exit_all_widgets = filesel_data->exit_all_widgets;
481 title = filesel_data->title;
482
483 #if !defined AMIGA && !defined __MORPHOS__
484 #ifdef WIN32
485 if( !is_drivesel ) {
486 directory = widget_getcwd();
487 if( directory == NULL ) return 1;
488 } else {
489 directory = NULL;
490 }
491 #else /* #ifdef WIN32 */
492 directory = widget_getcwd();
493 if( directory == NULL ) return 1;
494 #endif /* #ifdef WIN32 */
495
496 widget_scan( directory );
497 new_current_file = current_file = 0;
498 top_left_file = 0;
499
500 /* Create the dialog box */
501 error = widget_dialog_with_border( 1, 2, 30, 22 );
502 if( error ) {
503 free( directory );
504 return error;
505 }
506
507 #ifdef WIN32
508 if( directory == NULL ) {
509 directory = utils_safe_strdup( "Drive selection" );
510 }
511 #endif /* #ifdef WIN32 */
512
513 /* Show all the filenames */
514 widget_print_all_filenames( widget_filenames, widget_numfiles,
515 top_left_file, current_file, directory );
516
517 free( directory );
518
519 #endif /* ifndef AMIGA */
520
521 return 0;
522 }
523
524 int widget_filesel_finish( widget_finish_state finished ) {
525
526 /* Return with null if we didn't finish cleanly */
527 if( finished != WIDGET_FINISHED_OK ) {
528 if( widget_filesel_name ) free( widget_filesel_name );
529 widget_filesel_name = NULL;
530 }
531
532 return 0;
533 }
534
535 int
536 widget_filesel_load_draw( void *data )
537 {
538 is_saving = 0;
539 return widget_filesel_draw( data );
540 }
541
542 int
543 widget_filesel_save_draw( void *data )
544 {
545 is_saving = 1;
546 return widget_filesel_draw( data );
547 }
548
549 #if !defined AMIGA && !defined __MORPHOS__
550 static char* widget_getcwd( void )
551 {
552 char *directory; size_t directory_length;
553 char *ptr;
554
555 directory_length = 64;
556 directory = malloc( directory_length * sizeof( char ) );
557 if( directory == NULL ) {
558 return NULL;
559 }
560
561 do {
562 ptr = getcwd( directory, directory_length );
563 if( ptr ) break;
564 if( errno == ERANGE ) {
565 ptr = directory;
566 directory_length *= 2;
567 directory =
568 (char*)realloc( directory, directory_length * sizeof( char ) );
569 if( directory == NULL ) {
570 free( ptr );
571 return NULL;
572 }
573 } else {
574 free( directory );
575 return NULL;
576 }
577 } while(1);
578
579 #ifdef WIN32
580 if( directory[0] && directory[1] == ':' ) {
581 directory[0] = toupper( directory[0] );
582 }
583 #endif
584
585 return directory;
586 }
587
588 static int widget_print_all_filenames( struct widget_dirent **filenames, int n,
589 int top_left, int current,
590 const char *dir )
591 {
592 int i;
593 int error;
594
595 /* Give us a clean box to start with */
596 error = widget_dialog_with_border( 1, 2, 30, 22 );
597 if( error ) return error;
598
599 widget_printstring( 10, 16, WIDGET_COLOUR_TITLE, title );
600 if( widget_stringwidth( dir ) > 223 ) {
601 char buffer[128];
602 int prefix = widget_stringwidth( "..." ) + 1;
603 while( widget_stringwidth( dir ) > 223 - prefix ) dir++;
604 snprintf( buffer, sizeof( buffer ), "...%s", dir );
605 widget_print_title( 24, WIDGET_COLOUR_FOREGROUND, buffer );
606 } else {
607 widget_print_title( 24, WIDGET_COLOUR_FOREGROUND, dir );
608 }
609
610 if( top_left ) widget_up_arrow( 1, 5, WIDGET_COLOUR_FOREGROUND );
611
612 /* Print the filenames, mostly normally, but with the currently
613 selected file inverted */
614 for( i = top_left; i < n && i < top_left + ENTRIES_PER_SCREEN; i++ ) {
615 if( i == current ) {
616 widget_print_filename( filenames[i], i-top_left, 1 );
617 } else {
618 widget_print_filename( filenames[i], i-top_left, 0 );
619 }
620 }
621
622 if( is_saving )
623 {
624 widget_printstring( 12, 22 * 8, WIDGET_COLOUR_FOREGROUND,
625 "\012RETURN\001 = select" );
626 widget_printstring_right( 244, 22 * 8, WIDGET_COLOUR_FOREGROUND,
627 "\012TAB\001 = enter name" );
628 }
629
630 if( i < n )
631 widget_down_arrow( 1, is_saving ? 20 : 22, WIDGET_COLOUR_FOREGROUND );
632
633 /* Display that lot */
634 widget_display_lines( 2, 22 );
635
636 return 0;
637 }
638
639 /* Print a filename onto the dialog box */
640 static int widget_print_filename( struct widget_dirent *filename, int position,
641 int inverted )
642 {
643 char buffer[64], suffix[64], *dot = 0;
644 int width, suffix_width = 0;
645 int dir = S_ISDIR( filename->mode );
646 int truncated = 0, suffix_truncated = 0;
647
648 #define FILENAME_WIDTH 112
649 #define MAX_SUFFIX_WIDTH 56
650
651 int x = (position & 1) ? 132 : 16,
652 y = 40 + (position >> 1) * 8;
653
654 int foreground = WIDGET_COLOUR_FOREGROUND,
655
656 background = inverted ? WIDGET_COLOUR_HIGHLIGHT
657 : WIDGET_COLOUR_BACKGROUND;
658
659 widget_rectangle( x, y, FILENAME_WIDTH, 8, background );
660
661 strncpy( buffer, filename->name, sizeof( buffer ) - dir - 1);
662 buffer[sizeof( buffer ) - dir - 1] = '\0';
663
664 if (dir)
665 dir = widget_charwidth( FUSE_DIR_SEP_CHR );
666 else {
667 /* get filename extension */
668 dot = strrchr( filename->name, '.' );
669
670 /* if .gz or .bz2, we want the previous component too */
671 if( dot &&( !strcasecmp( dot, ".gz" ) || !strcasecmp( dot, ".bz2" ) ) ) {
672 char *olddot = dot;
673 *olddot = '\0';
674 dot = strrchr( filename->name, '.' );
675 *olddot = '.';
676 if (!dot)
677 dot = olddot;
678 }
679
680 /* if the dot is at the start of the name, ignore it */
681 if( dot == filename->name )
682 dot = 0;
683 }
684
685 if( dot ) {
686 /* split filename at extension separator */
687 if( dot - filename->name < sizeof( buffer ) )
688 buffer[dot - filename->name] = '\0';
689
690 /* get extension width (for display purposes) */
691 snprintf( suffix, sizeof( suffix ), "%s", dot );
692 while( ( suffix_width = ( dot && !dir )
693 ? widget_stringwidth( suffix ) : 0 ) > 110 ) {
694 suffix_truncated = 1;
695 suffix[strlen( suffix ) - 1] = '\0';
696 }
697 }
698
699 while( ( width = widget_stringwidth( buffer ) ) >=
700 FILENAME_WIDTH - dir - ( dot ? truncated + suffix_width : 0 ) ) {
701 truncated = 2;
702 if( suffix_width >= MAX_SUFFIX_WIDTH ) {
703 suffix_truncated = 2;
704 suffix[strlen (suffix) - 1] = '\0';
705 suffix_width = widget_stringwidth (suffix);
706 }
707 else
708 buffer[strlen (buffer) - 1] = '\0';
709 }
710 if( dir )
711 strcat (buffer, FUSE_DIR_SEP_STR );
712
713 widget_printstring( x + 1, y, foreground, buffer );
714 if( truncated )
715 widget_rectangle( x + width + 2, y, 1, 8, 4 );
716 if( dot )
717 widget_printstring( x + width + 2 + truncated, y,
718 foreground ^ 2, suffix );
719 if( suffix_truncated )
720 widget_rectangle( x + FILENAME_WIDTH, y, 1, 8, 4 );
721
722 return 0;
723 }
724 #endif /* ifndef AMIGA */
725
726 #ifdef WIN32
727 static void
728 widget_filesel_chdrv( void )
729 {
730 char *fn;
731
732 if( chdir( widget_filenames[ current_file ]->name ) ) {
733 ui_error( UI_ERROR_ERROR, "Could not change directory" );
734 return;
735 }
736
737 is_drivesel = 0;
738 fn = widget_getcwd();
739 widget_scan( fn ); free( fn );
740 new_current_file = 0;
741 /* Force a redisplay of all filenames */
742 current_file = 1; top_left_file = 1;
743 }
744
745 static void
746 widget_filesel_drvlist( void )
747 {
748 is_drivesel = 1;
749 widget_scan( NULL );
750 new_current_file = 0;
751 /* Force a redisplay of all filenames */
752 current_file = 1; top_left_file = 1;
753 }
754 #endif /* #ifdef WIN32 */
755
756 static int
757 widget_filesel_chdir( void )
758 {
759 char *fn, *ptr;
760
761 /* Get the new directory name */
762 fn = widget_getcwd();
763 if( fn == NULL ) {
764 widget_end_widget( WIDGET_FINISHED_CANCEL );
765 return 1;
766 }
767 ptr = fn;
768 fn = realloc( fn,
769 ( strlen( fn ) + 1 + strlen( widget_filenames[ current_file ]->name ) +
770 1 ) * sizeof(char)
771 );
772 if( fn == NULL ) {
773 free( ptr );
774 widget_end_widget( WIDGET_FINISHED_CANCEL );
775 return 1;
776 }
777 #ifndef GEKKO
778 /* Wii getcwd() already has the slash on the end */
779 strcat( fn, FUSE_DIR_SEP_STR );
780 #endif /* #ifndef GEKKO */
781 strcat( fn, widget_filenames[ current_file ]->name );
782
783 /*
784 in Win32 errno resulting from chdir on file is EINVAL which may mean many things
785 this will not be fixed in mingw - must use native function instead
786 http://thread.gmane.org/gmane.comp.gnu.mingw.user/9197
787 */
788
789 if( chdir( fn ) == -1 ) {
790 #ifndef WIN32
791 if( errno == ENOTDIR ) {
792 #else /* #ifndef WIN32 */
793 if( GetFileAttributes( fn ) != FILE_ATTRIBUTE_DIRECTORY ) {
794 #endif /* #ifndef WIN32 */
795 widget_filesel_name = fn; fn = NULL;
796 if( exit_all_widgets ) {
797 widget_end_all( WIDGET_FINISHED_OK );
798 } else {
799 widget_end_widget( WIDGET_FINISHED_OK );
800 }
801 }
802 } else {
803 widget_scan( fn );
804 new_current_file = 0;
805 /* Force a redisplay of all filenames */
806 current_file = 1; top_left_file = 1;
807 }
808
809 free( fn );
810
811 return 0;
812 }
813
814 void
815 widget_filesel_keyhandler( input_key key )
816 {
817 #if !defined AMIGA && !defined __MORPHOS__
818 char *fn, *ptr;
819 char *dirtitle;
820 #endif
821
822 /* If there are no files (possible on the Wii), can't really do anything */
823 if( widget_numfiles == 0 ) {
824 if( key == INPUT_KEY_Escape ) widget_end_widget( WIDGET_FINISHED_CANCEL );
825 return;
826 }
827
828 #if defined AMIGA || defined __MORPHOS__
829 if( exit_all_widgets ) {
830 widget_end_all( err );
831 } else {
832 widget_end_widget( err );
833 }
834 #else /* ifndef AMIGA */
835
836 new_current_file = current_file;
837
838 switch(key) {
839
840 #if 0
841 case INPUT_KEY_Resize: /* Fake keypress used on window resize */
842 widget_dialog_with_border( 1, 2, 30, 20 );
843 widget_print_all_filenames( widget_filenames, widget_numfiles,
844 top_left_file, current_file );
845 break;
846 #endif
847
848 case INPUT_KEY_Escape:
849 case INPUT_JOYSTICK_FIRE_2:
850 widget_end_widget( WIDGET_FINISHED_CANCEL );
851 break;
852
853 case INPUT_KEY_Left:
854 case INPUT_KEY_5:
855 case INPUT_KEY_h:
856 case INPUT_JOYSTICK_LEFT:
857 if( current_file > 0 ) new_current_file--;
858 break;
859
860 case INPUT_KEY_Down:
861 case INPUT_KEY_6:
862 case INPUT_KEY_j:
863 case INPUT_JOYSTICK_DOWN:
864 if( current_file+2 < widget_numfiles ) new_current_file += 2;
865 break;
866
867 case INPUT_KEY_Up:
868 case INPUT_KEY_7: /* Up */
869 case INPUT_KEY_k:
870 case INPUT_JOYSTICK_UP:
871 if( current_file > 1 ) new_current_file -= 2;
872 break;
873
874 case INPUT_KEY_Right:
875 case INPUT_KEY_8:
876 case INPUT_KEY_l:
877 case INPUT_JOYSTICK_RIGHT:
878 if( current_file < widget_numfiles-1 ) new_current_file++;
879 break;
880
881 case INPUT_KEY_Page_Up:
882 new_current_file = ( current_file > ENTRIES_PER_SCREEN ) ?
883 current_file - ENTRIES_PER_SCREEN :
884 0;
885 break;
886
887 case INPUT_KEY_Page_Down:
888 new_current_file = current_file + ENTRIES_PER_SCREEN;
889 if( new_current_file >= widget_numfiles )
890 new_current_file = widget_numfiles - 1;
891 break;
892
893 case INPUT_KEY_Home:
894 new_current_file = 0;
895 break;
896
897 case INPUT_KEY_End:
898 new_current_file = widget_numfiles - 1;
899 break;
900
901 case INPUT_KEY_Tab:
902 if( is_saving ) {
903 widget_text_t text_data;
904 text_data.title = title;
905 text_data.allow = WIDGET_INPUT_ASCII;
906 text_data.max_length = 30;
907 text_data.text[0] = 0;
908 if( widget_do_text( &text_data ) ||
909 !widget_text_text || !*widget_text_text )
910 break;
911 if( !compat_is_absolute_path( widget_text_text ) ) {
912 /* relative name */
913 /* Get current dir name and allocate space for the leafname */
914 fn = widget_getcwd();
915 ptr = fn;
916 if( fn )
917 fn = realloc( fn, strlen( fn ) + strlen( widget_text_text ) + 2 );
918 if( !fn ) {
919 free( ptr );
920 widget_end_widget( WIDGET_FINISHED_CANCEL );
921 return;
922 }
923 /* Append the leafname and return it */
924 strcat( fn, FUSE_DIR_SEP_STR );
925 strcat( fn, widget_text_text );
926 } else { /* absolute name */
927 fn = utils_safe_strdup( widget_text_text );
928 }
929 widget_filesel_name = fn;
930 if( exit_all_widgets ) {
931 widget_end_all( WIDGET_FINISHED_OK );
932 } else {
933 widget_end_widget( WIDGET_FINISHED_OK );
934 }
935 }
936 break;
937
938 case INPUT_KEY_Return:
939 case INPUT_KEY_KP_Enter:
940 case INPUT_JOYSTICK_FIRE_1:
941 #ifdef WIN32
942 if( is_drivesel ) {
943 widget_filesel_chdrv();
944 } else if( is_rootdir &&
945 !strcmp( widget_filenames[ current_file ]->name, ".." ) ) {
946 widget_filesel_drvlist();
947 } else {
948 #endif /* #ifdef WIN32 */
949 if( widget_filesel_chdir() ) return;
950 #ifdef WIN32
951 }
952 #endif /* #ifdef WIN32 */
953 break;
954
955 default: /* Keep gcc happy */
956 break;
957
958 }
959
960 #ifdef WIN32
961 if( is_drivesel ) {
962 dirtitle = utils_safe_strdup( "Drive selection" );
963 } else {
964 #endif /* #ifdef WIN32 */
965 dirtitle = widget_getcwd();
966 #ifdef WIN32
967 }
968 #endif /* #ifdef WIN32 */
969
970 /* If we moved the cursor */
971 if( new_current_file != current_file ) {
972
973 /* If we've got off the top or bottom of the currently displayed
974 file list, then reset the top-left corner and display the whole
975 thing */
976 if( new_current_file < top_left_file ) {
977
978 top_left_file = new_current_file & ~1;
979 widget_print_all_filenames( widget_filenames, widget_numfiles,
980 top_left_file, new_current_file, dirtitle );
981
982 } else if( new_current_file >= top_left_file+ENTRIES_PER_SCREEN ) {
983
984 top_left_file = new_current_file & ~1;
985 top_left_file -= ENTRIES_PER_SCREEN - 2;
986 widget_print_all_filenames( widget_filenames, widget_numfiles,
987 top_left_file, new_current_file, dirtitle );
988
989 } else {
990
991 /* Otherwise, print the current file uninverted and the
992 new current file inverted */
993
994 widget_print_filename( widget_filenames[ current_file ],
995 current_file - top_left_file, 0 );
996
997 widget_print_filename( widget_filenames[ new_current_file ],
998 new_current_file - top_left_file, 1 );
999
1000 widget_display_lines( 2, 21 );
1001 }
1002
1003 /* Reset the current file marker */
1004 current_file = new_current_file;
1005
1006 }
1007
1008 free( dirtitle );
1009 #endif /* ifdef AMIGA */
1010 }
1011