summaryrefslogtreecommitdiff
path: root/apps/tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/tree.c')
-rw-r--r--apps/tree.c477
1 files changed, 231 insertions, 246 deletions
diff --git a/apps/tree.c b/apps/tree.c
index f7a83de85f..29ca4dfe15 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -66,10 +66,6 @@ static int max_files_in_dir;
66static char *name_buffer; 66static char *name_buffer;
67static int name_buffer_size; /* Size of allocated buffer */ 67static int name_buffer_size; /* Size of allocated buffer */
68static int name_buffer_length; /* Currently used amount */ 68static int name_buffer_length; /* Currently used amount */
69struct entry {
70 short attr; /* FAT attributes + file type flags */
71 char *name;
72};
73 69
74static struct entry *dircache; 70static struct entry *dircache;
75 71
@@ -87,6 +83,8 @@ static int boot_size = 0;
87static int boot_cluster; 83static int boot_cluster;
88static bool boot_changed = false; 84static bool boot_changed = false;
89 85
86static bool dirbrowse(char *root);
87
90void browse_root(void) 88void browse_root(void)
91{ 89{
92#ifndef SIMULATOR 90#ifndef SIMULATOR
@@ -158,14 +156,13 @@ static int build_playlist(int start_index)
158 int i; 156 int i;
159 int start=start_index; 157 int start=start_index;
160 158
161 playlist_clear();
162
163 for(i = 0;i < filesindir;i++) 159 for(i = 0;i < filesindir;i++)
164 { 160 {
165 if(dircache[i].attr & TREE_ATTR_MPA) 161 if(dircache[i].attr & TREE_ATTR_MPA)
166 { 162 {
167 DEBUGF("Adding %s\n", dircache[i].name); 163 DEBUGF("Adding %s\n", dircache[i].name);
168 playlist_add(dircache[i].name); 164 if (playlist_add(dircache[i].name) < 0)
165 break;
169 } 166 }
170 else 167 else
171 { 168 {
@@ -237,6 +234,133 @@ static void showfileline(int line, int direntry, bool scroll)
237 } 234 }
238} 235}
239 236
237/* load sorted directory into dircache. returns NULL on failure. */
238struct entry* load_and_sort_directory(char *dirname, int dirfilter,
239 int *num_files, bool *buffer_full)
240{
241 int i;
242
243 DIR *dir = opendir(dirname);
244 if(!dir)
245 return NULL; /* not a directory */
246
247 name_buffer_length = 0;
248 *buffer_full = false;
249
250 for ( i=0; i < max_files_in_dir; i++ ) {
251 int len;
252 struct dirent *entry = readdir(dir);
253 struct entry* dptr = &dircache[i];
254 if (!entry)
255 break;
256
257 len = strlen(entry->d_name);
258
259 /* skip directories . and .. */
260 if ((entry->attribute & ATTR_DIRECTORY) &&
261 (((len == 1) &&
262 (!strncmp(entry->d_name, ".", 1))) ||
263 ((len == 2) &&
264 (!strncmp(entry->d_name, "..", 2))))) {
265 i--;
266 continue;
267 }
268
269 /* Skip FAT volume ID */
270 if (entry->attribute & ATTR_VOLUME_ID) {
271 i--;
272 continue;
273 }
274
275 /* filter out dotfiles and hidden files */
276 if (dirfilter != SHOW_ALL &&
277 ((entry->d_name[0]=='.') ||
278 (entry->attribute & ATTR_HIDDEN))) {
279 i--;
280 continue;
281 }
282
283 dptr->attr = entry->attribute;
284
285 /* mark mp? and m3u files as such */
286 if ( !(dptr->attr & ATTR_DIRECTORY) && (len > 4) ) {
287 if (!strcasecmp(&entry->d_name[len-4], ".mp3") ||
288 (!strcasecmp(&entry->d_name[len-4], ".mp2")) ||
289 (!strcasecmp(&entry->d_name[len-4], ".mpa")))
290 dptr->attr |= TREE_ATTR_MPA;
291 else if (!strcasecmp(&entry->d_name[len-4], ".m3u"))
292 dptr->attr |= TREE_ATTR_M3U;
293 else if (!strcasecmp(&entry->d_name[len-4], ".cfg"))
294 dptr->attr |= TREE_ATTR_CFG;
295 else if (!strcasecmp(&entry->d_name[len-4], ".wps"))
296 dptr->attr |= TREE_ATTR_WPS;
297 else if (!strcasecmp(&entry->d_name[len-4], ".txt"))
298 dptr->attr |= TREE_ATTR_TXT;
299 else if (!strcasecmp(&entry->d_name[len-4], ".lng"))
300 dptr->attr |= TREE_ATTR_LNG;
301#ifdef HAVE_RECORDER_KEYPAD
302 else if (!strcasecmp(&entry->d_name[len-4], ".fnt"))
303 dptr->attr |= TREE_ATTR_FONT;
304 else if (!strcasecmp(&entry->d_name[len-4], ".ajz"))
305#else
306 else if (!strcasecmp(&entry->d_name[len-4], ".mod"))
307#endif
308 dptr->attr |= TREE_ATTR_MOD;
309 else if (!strcasecmp(&entry->d_name[len-5], ".rock"))
310 dptr->attr |= TREE_ATTR_ROCK;
311 }
312
313 /* memorize/compare details about the boot file */
314 if ((currdir[1] == 0) && !strcmp(entry->d_name, BOOTFILE)) {
315 if (boot_size) {
316 if ((entry->size != boot_size) ||
317 (entry->startcluster != boot_cluster))
318 boot_changed = true;
319 }
320 boot_size = entry->size;
321 boot_cluster = entry->startcluster;
322 }
323
324 /* filter out all non-playlist files */
325 if ( dirfilter == SHOW_PLAYLIST &&
326 (!(dptr->attr &
327 (ATTR_DIRECTORY|TREE_ATTR_M3U))) ) {
328 i--;
329 continue;
330 }
331
332 /* filter out non-music files */
333 if ( dirfilter == SHOW_MUSIC &&
334 (!(dptr->attr &
335 (ATTR_DIRECTORY|TREE_ATTR_MPA|TREE_ATTR_M3U))) ) {
336 i--;
337 continue;
338 }
339
340 /* filter out non-supported files */
341 if ( dirfilter == SHOW_SUPPORTED &&
342 (!(dptr->attr & TREE_ATTR_MASK)) ) {
343 i--;
344 continue;
345 }
346
347 if (len > name_buffer_size - name_buffer_length - 1) {
348 /* Tell the world that we ran out of buffer space */
349 *buffer_full = true;
350 break;
351 }
352 dptr->name = &name_buffer[name_buffer_length];
353 strcpy(dptr->name,entry->d_name);
354 name_buffer_length += len + 1;
355 }
356 *num_files = i;
357 closedir(dir);
358 strncpy(lastdir,dirname,sizeof(lastdir));
359 lastdir[sizeof(lastdir)-1] = 0;
360 qsort(dircache,i,sizeof(struct entry),compare);
361
362 return dircache;
363}
240 364
241static int showdir(char *path, int start) 365static int showdir(char *path, int start)
242{ 366{
@@ -258,124 +382,9 @@ static int showdir(char *path, int start)
258 382
259 /* new dir? cache it */ 383 /* new dir? cache it */
260 if (strncmp(path,lastdir,sizeof(lastdir)) || reload_dir) { 384 if (strncmp(path,lastdir,sizeof(lastdir)) || reload_dir) {
261 DIR *dir = opendir(path); 385 if (!load_and_sort_directory(path, global_settings.dirfilter,
262 if(!dir) 386 &filesindir, &dir_buffer_full))
263 return -1; /* not a directory */ 387 return -1;
264
265 name_buffer_length = 0;
266 dir_buffer_full = false;
267
268 for ( i=0; i < max_files_in_dir; i++ ) {
269 int len;
270 struct dirent *entry = readdir(dir);
271 struct entry* dptr = &dircache[i];
272 if (!entry)
273 break;
274
275 len = strlen(entry->d_name);
276
277 /* skip directories . and .. */
278 if ((entry->attribute & ATTR_DIRECTORY) &&
279 (((len == 1) &&
280 (!strncmp(entry->d_name, ".", 1))) ||
281 ((len == 2) &&
282 (!strncmp(entry->d_name, "..", 2))))) {
283 i--;
284 continue;
285 }
286
287 /* Skip FAT volume ID */
288 if (entry->attribute & ATTR_VOLUME_ID) {
289 i--;
290 continue;
291 }
292
293 /* filter out dotfiles and hidden files */
294 if (global_settings.dirfilter != SHOW_ALL &&
295 ((entry->d_name[0]=='.') ||
296 (entry->attribute & ATTR_HIDDEN))) {
297 i--;
298 continue;
299 }
300
301 dptr->attr = entry->attribute;
302
303 /* mark mp? and m3u files as such */
304 if ( !(dptr->attr & ATTR_DIRECTORY) && (len > 4) ) {
305 if (!strcasecmp(&entry->d_name[len-4], ".mp3") ||
306 (!strcasecmp(&entry->d_name[len-4], ".mp2")) ||
307 (!strcasecmp(&entry->d_name[len-4], ".mpa")))
308 dptr->attr |= TREE_ATTR_MPA;
309 else if (!strcasecmp(&entry->d_name[len-4], ".m3u"))
310 dptr->attr |= TREE_ATTR_M3U;
311 else if (!strcasecmp(&entry->d_name[len-4], ".cfg"))
312 dptr->attr |= TREE_ATTR_CFG;
313 else if (!strcasecmp(&entry->d_name[len-4], ".wps"))
314 dptr->attr |= TREE_ATTR_WPS;
315 else if (!strcasecmp(&entry->d_name[len-4], ".txt"))
316 dptr->attr |= TREE_ATTR_TXT;
317 else if (!strcasecmp(&entry->d_name[len-4], ".lng"))
318 dptr->attr |= TREE_ATTR_LNG;
319#ifdef HAVE_RECORDER_KEYPAD
320 else if (!strcasecmp(&entry->d_name[len-4], ".fnt"))
321 dptr->attr |= TREE_ATTR_FONT;
322 else if (!strcasecmp(&entry->d_name[len-4], ".ajz"))
323#else
324 else if (!strcasecmp(&entry->d_name[len-4], ".mod"))
325#endif
326 dptr->attr |= TREE_ATTR_MOD;
327 else if (!strcasecmp(&entry->d_name[len-5], ".rock"))
328 dptr->attr |= TREE_ATTR_ROCK;
329 }
330
331 /* memorize/compare details about the boot file */
332 if ((currdir[1] == 0) && !strcmp(entry->d_name, BOOTFILE)) {
333 if (boot_size) {
334 if ((entry->size != boot_size) ||
335 (entry->startcluster != boot_cluster))
336 boot_changed = true;
337 }
338 boot_size = entry->size;
339 boot_cluster = entry->startcluster;
340 }
341
342 /* filter out all non-playlist files */
343 if ( global_settings.dirfilter == SHOW_PLAYLIST &&
344 (!(dptr->attr &
345 (ATTR_DIRECTORY|TREE_ATTR_M3U))) ) {
346 i--;
347 continue;
348 }
349
350 /* filter out non-music files */
351 if ( global_settings.dirfilter == SHOW_MUSIC &&
352 (!(dptr->attr &
353 (ATTR_DIRECTORY|TREE_ATTR_MPA|TREE_ATTR_M3U))) ) {
354 i--;
355 continue;
356 }
357
358 /* filter out non-supported files */
359 if ( global_settings.dirfilter == SHOW_SUPPORTED &&
360 (!(dptr->attr & TREE_ATTR_MASK)) ) {
361 i--;
362 continue;
363 }
364
365 if (len > name_buffer_size - name_buffer_length - 1) {
366 /* Tell the world that we ran out of buffer space */
367 dir_buffer_full = true;
368 break;
369 }
370 dptr->name = &name_buffer[name_buffer_length];
371 strcpy(dptr->name,entry->d_name);
372 name_buffer_length += len + 1;
373 }
374 filesindir = i;
375 closedir(dir);
376 strncpy(lastdir,path,sizeof(lastdir));
377 lastdir[sizeof(lastdir)-1] = 0;
378 qsort(dircache,filesindir,sizeof(struct entry),compare);
379 388
380 if ( dir_buffer_full || filesindir == max_files_in_dir ) { 389 if ( dir_buffer_full || filesindir == max_files_in_dir ) {
381#ifdef HAVE_LCD_CHARCELLS 390#ifdef HAVE_LCD_CHARCELLS
@@ -531,7 +540,7 @@ static int showdir(char *path, int start)
531 return filesindir; 540 return filesindir;
532} 541}
533 542
534bool ask_resume(void) 543static bool ask_resume(void)
535{ 544{
536#ifdef HAVE_LCD_CHARCELLS 545#ifdef HAVE_LCD_CHARCELLS
537 lcd_double_height(false); 546 lcd_double_height(false);
@@ -570,92 +579,62 @@ bool ask_resume(void)
570 return false; 579 return false;
571} 580}
572 581
573void start_resume(void) 582/* load tracks from specified directory to resume play */
583void resume_directory(char *dir)
584{
585 bool buffer_full;
586
587 if (!load_and_sort_directory(dir, global_settings.dirfilter, &filesindir,
588 &buffer_full))
589 return;
590 lastdir[0] = 0;
591
592 build_playlist(0);
593}
594
595/* Returns the current working directory and also writes cwd to buf if
596 non-NULL. In case of error, returns NULL. */
597char *getcwd(char *buf, int size)
598{
599 if (!buf)
600 return currdir;
601 else if (size > 0)
602 {
603 strncpy(buf, currdir, size);
604 return buf;
605 }
606 else
607 return NULL;
608}
609
610/* Force a reload of the directory next time directory browser is called */
611void reload_directory(void)
612{
613 reload_dir = true;
614}
615
616static void start_resume(void)
574{ 617{
575 if ( global_settings.resume && 618 if ( global_settings.resume &&
576 global_settings.resume_index != -1 ) { 619 global_settings.resume_index != -1 ) {
577 int len = strlen(global_settings.resume_file);
578
579 DEBUGF("Resume file %s\n",global_settings.resume_file);
580 DEBUGF("Resume index %X offset %X\n", 620 DEBUGF("Resume index %X offset %X\n",
581 global_settings.resume_index, 621 global_settings.resume_index,
582 global_settings.resume_offset); 622 global_settings.resume_offset);
583 DEBUGF("Resume shuffle %s seed %X\n",
584 global_settings.playlist_shuffle?"on":"off",
585 global_settings.resume_seed);
586
587 /* playlist? */
588 if (!strcasecmp(&global_settings.resume_file[len-4], ".m3u")) {
589 char* slash;
590
591 /* check that the file exists */
592 int fd = open(global_settings.resume_file, O_RDONLY);
593 if(fd<0)
594 return;
595 close(fd);
596
597 if (!ask_resume())
598 return;
599
600 slash = strrchr(global_settings.resume_file,'/');
601 if (slash) {
602 *slash=0;
603 play_list(global_settings.resume_file,
604 slash+1,
605 global_settings.resume_index,
606 true, /* the index is AFTER shuffle */
607 global_settings.resume_offset,
608 global_settings.resume_seed,
609 global_settings.resume_first_index,
610 global_settings.queue_resume,
611 global_settings.queue_resume_index);
612 *slash='/';
613 }
614 else {
615 /* check that the dir exists */
616 DIR* dir = opendir(global_settings.resume_file);
617 if(!dir)
618 return;
619 closedir(dir);
620
621 if (!ask_resume())
622 return;
623
624 play_list("/",
625 global_settings.resume_file,
626 global_settings.resume_index,
627 true,
628 global_settings.resume_offset,
629 global_settings.resume_seed,
630 global_settings.resume_first_index,
631 global_settings.queue_resume,
632 global_settings.queue_resume_index);
633 }
634 }
635 else {
636 if (!ask_resume())
637 return;
638
639 if (showdir(global_settings.resume_file, 0) < 0 )
640 return;
641
642 lastdir[0] = '\0';
643
644 build_playlist(global_settings.resume_index);
645 play_list(global_settings.resume_file,
646 NULL,
647 global_settings.resume_index,
648 true,
649 global_settings.resume_offset,
650 global_settings.resume_seed,
651 global_settings.resume_first_index,
652 global_settings.queue_resume,
653 global_settings.queue_resume_index);
654 }
655 623
656 status_set_playmode(STATUS_PLAY); 624 if (!ask_resume())
657 status_draw(true); 625 return;
658 wps_show(); 626
627 if (playlist_resume() != -1)
628 {
629 playlist_start(global_settings.resume_index,
630 global_settings.resume_offset);
631
632 status_set_playmode(STATUS_PLAY);
633 status_draw(true);
634 wps_show();
635 }
636 else
637 return;
659 } 638 }
660} 639}
661 640
@@ -751,19 +730,33 @@ static bool handle_on(int* ds, int* dc, int numentries, int tree_max_on_screen)
751 730
752 case BUTTON_PLAY: 731 case BUTTON_PLAY:
753 case BUTTON_RC_PLAY: 732 case BUTTON_RC_PLAY:
754 case BUTTON_ON | BUTTON_PLAY: 733 case BUTTON_ON | BUTTON_PLAY: {
734 int onplay_result;
735
755 if (currdir[1]) 736 if (currdir[1])
756 snprintf(buf, sizeof buf, "%s/%s", 737 snprintf(buf, sizeof buf, "%s/%s",
757 currdir, dircache[dircursor+dirstart].name); 738 currdir, dircache[dircursor+dirstart].name);
758 else 739 else
759 snprintf(buf, sizeof buf, "/%s", 740 snprintf(buf, sizeof buf, "/%s",
760 dircache[dircursor+dirstart].name); 741 dircache[dircursor+dirstart].name);
761 if (onplay(buf, dircache[dircursor+dirstart].attr)) 742 onplay_result = onplay(buf,
762 reload_dir = 1; 743 dircache[dircursor+dirstart].attr);
744 switch (onplay_result)
745 {
746 case ONPLAY_OK:
747 used = true;
748 break;
749 case ONPLAY_RELOAD_DIR:
750 reload_dir = 1;
751 used = true;
752 break;
753 case ONPLAY_START_PLAY:
754 used = false; /* this will enable the wps */
755 break;
756 }
763 exit = true; 757 exit = true;
764 used = true;
765 break; 758 break;
766 759 }
767 case BUTTON_ON | BUTTON_REL: 760 case BUTTON_ON | BUTTON_REL:
768 case BUTTON_ON | TREE_PREV | BUTTON_REL: 761 case BUTTON_ON | TREE_PREV | BUTTON_REL:
769 case BUTTON_ON | TREE_NEXT | BUTTON_REL: 762 case BUTTON_ON | TREE_NEXT | BUTTON_REL:
@@ -793,7 +786,7 @@ static bool handle_on(int* ds, int* dc, int numentries, int tree_max_on_screen)
793 return used; 786 return used;
794} 787}
795 788
796bool dirbrowse(char *root) 789static bool dirbrowse(char *root)
797{ 790{
798 int numentries=0; 791 int numentries=0;
799 char buf[MAX_PATH]; 792 char buf[MAX_PATH];
@@ -934,41 +927,36 @@ bool dirbrowse(char *root)
934 lcd_stop_scroll(); 927 lcd_stop_scroll();
935 switch ( file->attr & TREE_ATTR_MASK ) { 928 switch ( file->attr & TREE_ATTR_MASK ) {
936 case TREE_ATTR_M3U: 929 case TREE_ATTR_M3U:
937 if ( global_settings.resume ) { 930 if (playlist_create(currdir, file->name) != -1)
938 if (currdir[1]) 931 {
939 snprintf(global_settings.resume_file, 932 if (global_settings.playlist_shuffle)
940 MAX_PATH, "%s/%s", 933 playlist_shuffle(seed, -1);
941 currdir, file->name); 934 start_index = 0;
942 else 935 playlist_start(start_index,0);
943 snprintf(global_settings.resume_file, 936 play = true;
944 MAX_PATH, "/%s", file->name);
945 } 937 }
946 play_list(currdir, file->name, 0, false, 0,
947 seed, 0, 0, -1);
948 start_index = 0;
949 play = true;
950 break; 938 break;
951 939
952 case TREE_ATTR_MPA: 940 case TREE_ATTR_MPA:
953 if ( global_settings.resume ) 941 if (playlist_create(currdir, NULL) != -1)
954 strncpy(global_settings.resume_file, 942 {
955 currdir, MAX_PATH); 943 start_index =
956 944 build_playlist(dircursor+dirstart);
957 start_index = 945 if (global_settings.playlist_shuffle)
958 build_playlist(dircursor+dirstart); 946 {
959 947 start_index =
960 /* when shuffling dir.: play all files even if the 948 playlist_shuffle(seed,start_index);
961 file selected by user is not the first one */ 949
962 if (global_settings.playlist_shuffle 950 /* when shuffling dir.: play all files
963 && !global_settings.play_selected) 951 even if the file selected by user is
964 start_index = 0; 952 not the first one */
965 953 if (!global_settings.play_selected)
966 /* it is important that we get back the index 954 start_index = 0;
967 in the (shuffled) list and store that */ 955 }
968 start_index = play_list(currdir, NULL, 956
969 start_index, false, 957 playlist_start(start_index, 0);
970 0, seed, 0, 0, -1); 958 play = true;
971 play = true; 959 }
972 break; 960 break;
973 961
974 /* wps config file */ 962 /* wps config file */
@@ -1055,9 +1043,6 @@ bool dirbrowse(char *root)
1055 shuffled list in case shuffle is enabled */ 1043 shuffled list in case shuffle is enabled */
1056 global_settings.resume_index = start_index; 1044 global_settings.resume_index = start_index;
1057 global_settings.resume_offset = 0; 1045 global_settings.resume_offset = 0;
1058 global_settings.resume_first_index =
1059 playlist_first_index();
1060 global_settings.resume_seed = seed;
1061 settings_save(); 1046 settings_save();
1062 } 1047 }
1063 1048