Re-add the lseek to the beginning of the file which was accidentally removed.
[kugel-rb.git] / apps / plugins / random_folder_advance_config.c
blobeca33dc08a7c7bd4895a3020a8df92f3f6671304
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Jonathan Gordon
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "plugin.h"
22 #include "file.h"
26 static bool cancel;
27 static int fd;
28 static int dirs_count;
29 static int lasttick;
30 #define RFA_FILE ROCKBOX_DIR "/folder_advance_list.dat"
31 #define RFADIR_FILE ROCKBOX_DIR "/folder_advance_dir.txt"
32 #define RFA_FILE_TEXT ROCKBOX_DIR "/folder_advance_list.txt"
33 #define MAX_REMOVED_DIRS 10
35 char *buffer = NULL;
36 size_t buffer_size;
37 int num_replaced_dirs = 0;
38 char removed_dirs[MAX_REMOVED_DIRS][MAX_PATH];
39 struct file_format {
40 int count;
41 char folder[][MAX_PATH];
43 struct file_format *list = NULL;
45 void update_screen(bool clear)
47 char buf[15];
48 int i;
50 rb->snprintf(buf,sizeof(buf),"Folders: %d",dirs_count);
51 FOR_NB_SCREENS(i)
53 if(clear)
54 rb->screens[i]->clear_display();
55 rb->screens[i]->putsxy(0,0,buf);
56 rb->screens[i]->update();
60 void traversedir(char* location, char* name)
62 struct dirent *entry;
63 DIR* dir;
64 char fullpath[MAX_PATH], path[MAX_PATH];
65 bool check = false;
66 int i;
68 rb->snprintf(fullpath, sizeof(fullpath), "%s/%s", location, name);
69 dir = rb->opendir(fullpath);
70 if (dir) {
71 entry = rb->readdir(dir);
72 while (entry) {
73 if (cancel)
74 break;
75 /* Skip .. and . */
76 if (entry->d_name[0] == '.')
78 if ( !rb->strcmp(entry->d_name,".")
79 || !rb->strcmp(entry->d_name,"..")
80 || !rb->strcmp(entry->d_name,".rockbox"))
81 check = false;
82 else check = true;
84 else check = true;
86 /* check if path is removed directory, if so dont enter it */
87 rb->snprintf(path, MAX_PATH, "%s/%s", fullpath, entry->d_name);
88 while(path[0] == '/')
89 rb->strlcpy(path, path + 1, sizeof(path));
90 for(i = 0; i < num_replaced_dirs; i++)
92 if(!rb->strcmp(path, removed_dirs[i]))
94 check = false;
95 break;
99 if (check)
101 struct dirinfo info = rb->dir_get_info(dir, entry);
102 if (info.attribute & ATTR_DIRECTORY) {
103 char *start;
104 dirs_count++;
105 rb->snprintf(path,MAX_PATH,"%s/%s",fullpath,entry->d_name);
106 start = &path[rb->strlen(path)];
107 rb->memset(start,0,&path[MAX_PATH-1]-start);
108 rb->write(fd,path,MAX_PATH);
109 traversedir(fullpath, entry->d_name);
112 if (*rb->current_tick - lasttick > (HZ/2)) {
113 update_screen(false);
114 lasttick = *rb->current_tick;
115 if (rb->action_userabort(TIMEOUT_NOBLOCK))
117 cancel = true;
118 break;
122 entry = rb->readdir(dir);
124 rb->closedir(dir);
128 bool custom_dir(void)
130 DIR* dir_check;
131 char *starts, line[MAX_PATH], formatted_line[MAX_PATH];
132 static int fd2;
133 char buf[11];
134 int i, errors = 0;
136 /* populate removed dirs array */
137 if((fd2 = rb->open(RFADIR_FILE,O_RDONLY)) >= 0)
139 while ((rb->read_line(fd2, line, MAX_PATH - 1)) > 0)
141 if ((line[0] == '-') && (line[1] == '/') &&
142 (num_replaced_dirs < MAX_REMOVED_DIRS))
144 num_replaced_dirs ++;
145 rb->strlcpy(removed_dirs[num_replaced_dirs - 1], line + 2,
146 sizeof(line));
149 rb->close(fd2);
152 if((fd2 = rb->open(RFADIR_FILE,O_RDONLY)) >= 0)
154 while ((rb->read_line(fd2, line, MAX_PATH - 1)) > 0)
156 /* blank lines and removed dirs ignored */
157 if (rb->strlen(line) && ((line[0] != '-') || (line[1] != '/')))
159 /* remove preceeding '/'s from the line */
160 while(line[0] == '/')
161 rb->strlcpy(line, line + 1, sizeof(line));
163 rb->snprintf(formatted_line, MAX_PATH, "/%s", line);
165 dir_check = rb->opendir(formatted_line);
167 if (dir_check)
169 rb->closedir(dir_check);
170 starts = &formatted_line[rb->strlen(formatted_line)];
171 rb->memset(starts, 0, &formatted_line[MAX_PATH-1]-starts);
172 bool write_line = true;
174 for(i = 0; i < num_replaced_dirs; i++)
176 if(!rb->strcmp(line, removed_dirs[i]))
178 write_line = false;
179 break;
183 if(write_line)
185 dirs_count++;
186 rb->write(fd, formatted_line, MAX_PATH);
189 traversedir("", line);
191 else
193 errors ++;
194 rb->snprintf(buf,sizeof(buf),"Not found:");
195 FOR_NB_SCREENS(i)
197 rb->screens[i]->puts(0,0,buf);
198 rb->screens[i]->puts(0, errors, line);
200 update_screen(false);
204 rb->close(fd2);
205 if(errors)
206 /* Press button to continue */
207 rb->get_action(CONTEXT_STD, TIMEOUT_BLOCK);
209 else
210 return false;
211 return true;
214 void generate(void)
216 dirs_count = 0;
217 cancel = false;
218 fd = rb->open(RFA_FILE,O_CREAT|O_WRONLY, 0666);
219 rb->write(fd,&dirs_count,sizeof(int));
220 if (fd < 0)
222 rb->splashf(HZ, "Couldnt open %s", RFA_FILE);
223 return;
225 #ifndef HAVE_LCD_CHARCELLS
226 update_screen(true);
227 #endif
228 lasttick = *rb->current_tick;
230 if(!custom_dir())
231 traversedir("", "");
233 rb->lseek(fd,0,SEEK_SET);
234 rb->write(fd,&dirs_count,sizeof(int));
235 rb->close(fd);
236 rb->splash(HZ, "Done");
239 static const char* list_get_name_cb(int selected_item, void* data,
240 char* buf, size_t buf_len)
242 (void)data;
243 rb->strlcpy(buf, list->folder[selected_item], buf_len);
244 return buf;
247 int load_list(void)
249 int myfd = rb->open(RFA_FILE,O_RDONLY);
250 if (myfd < 0)
251 return -1;
252 buffer = rb->plugin_get_audio_buffer(&buffer_size);
253 if (!buffer)
255 return -2;
258 rb->read(myfd,buffer,buffer_size);
259 rb->close(myfd);
260 list = (struct file_format *)buffer;
262 return 0;
265 int save_list(void)
267 int myfd = rb->creat(RFA_FILE, 0666);
268 if (myfd < 0)
270 rb->splash(HZ, "Could Not Open " RFA_FILE);
271 return -1;
273 int dirs_count = 0, i = 0;
274 rb->write(myfd,&dirs_count,sizeof(int));
275 for ( ;i<list->count;i++)
277 if (list->folder[i][0] != ' ')
279 dirs_count++;
280 rb->write(myfd,list->folder[i],MAX_PATH);
283 rb->lseek(myfd,0,SEEK_SET);
284 rb->write(myfd,&dirs_count,sizeof(int));
285 rb->close(myfd);
287 return 1;
290 int edit_list(void)
292 struct gui_synclist lists;
293 bool exit = false;
294 int button,i;
295 int selection, ret = 0;
297 /* load the dat file if not already done */
298 if ((list == NULL || list->count == 0) && (i = load_list()) != 0)
300 rb->splashf(HZ*2, "Could not load %s, rv = %d", RFA_FILE, i);
301 return -1;
304 dirs_count = list->count;
306 rb->gui_synclist_init(&lists,list_get_name_cb,0, false, 1, NULL);
307 rb->gui_synclist_set_icon_callback(&lists,NULL);
308 rb->gui_synclist_set_nb_items(&lists,list->count);
309 rb->gui_synclist_limit_scroll(&lists,true);
310 rb->gui_synclist_select_item(&lists, 0);
312 while (!exit)
314 rb->gui_synclist_draw(&lists);
315 button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
316 if (rb->gui_synclist_do_button(&lists,&button,LIST_WRAP_UNLESS_HELD))
317 continue;
318 selection = rb->gui_synclist_get_sel_pos(&lists);
319 switch (button)
321 case ACTION_STD_OK:
322 list->folder[selection][0] = ' ';
323 list->folder[selection][1] = '\0';
324 break;
325 case ACTION_STD_CONTEXT:
327 int len;
328 MENUITEM_STRINGLIST(menu, "Remove Menu", NULL,
329 "Remove Folder", "Remove Folder Tree");
331 switch (rb->do_menu(&menu, NULL, NULL, false))
333 case 0:
334 list->folder[selection][0] = ' ';
335 list->folder[selection][1] = '\0';
336 break;
337 case 1:
339 char temp[MAX_PATH];
340 rb->strcpy(temp,list->folder[selection]);
341 len = rb->strlen(temp);
342 for (i=0;i<list->count;i++)
344 if (!rb->strncmp(list->folder[i],temp,len))
346 list->folder[i][0] = ' ';
347 list->folder[i][1] = '\0';
351 break;
354 break;
355 case ACTION_STD_CANCEL:
357 MENUITEM_STRINGLIST(menu, "Exit Menu", NULL,
358 "Save and Exit", "Ignore Changes and Exit");
360 switch (rb->do_menu(&menu, NULL, NULL, false))
362 case 0:
363 save_list();
364 case 1:
365 exit = true;
366 ret = -2;
369 break;
372 return ret;
375 int export_list_to_file_text(void)
377 int i = 0;
378 /* load the dat file if not already done */
379 if ((list == NULL || list->count == 0) && (i = load_list()) != 0)
381 rb->splashf(HZ*2, "Could not load %s, rv = %d", RFA_FILE, i);
382 return 0;
385 if (list->count <= 0)
387 rb->splashf(HZ*2, "no dirs in list file: %s", RFA_FILE);
388 return 0;
391 /* create and open the file */
392 int myfd = rb->creat(RFA_FILE_TEXT, 0666);
393 if (myfd < 0)
395 rb->splashf(HZ*4, "failed to open: fd = %d, file = %s",
396 myfd, RFA_FILE_TEXT);
397 return -1;
400 /* write each directory to file */
401 for (i = 0; i < list->count; i++)
403 if (list->folder[i][0] != ' ')
405 rb->fdprintf(myfd, "%s\n", list->folder[i]);
409 rb->close(myfd);
410 rb->splash(HZ, "Done");
411 return 1;
414 int import_list_from_file_text(void)
416 char line[MAX_PATH];
418 buffer = rb->plugin_get_audio_buffer(&buffer_size);
419 if (buffer == NULL)
421 rb->splash(HZ*2, "failed to get audio buffer");
422 return -1;
425 int myfd = rb->open(RFA_FILE_TEXT, O_RDONLY);
426 if (myfd < 0)
428 rb->splashf(HZ*2, "failed to open: %s", RFA_FILE_TEXT);
429 return -1;
432 /* set the list structure, and initialize count */
433 list = (struct file_format *)buffer;
434 list->count = 0;
436 while ((rb->read_line(myfd, line, MAX_PATH - 1)) > 0)
438 /* copy the dir name, and skip the newline */
439 int len = rb->strlen(line);
440 /* remove CRs */
441 if (len > 0)
443 if (line[len-1] == 0x0A || line[len-1] == 0x0D)
444 line[len-1] = 0x00;
445 if (len > 1 &&
446 (line[len-2] == 0x0A || line[len-2] == 0x0D))
447 line[len-2] = 0x00;
450 rb->strcpy(list->folder[list->count++], line);
453 rb->close(myfd);
455 if (list->count == 0)
457 load_list();
459 else
461 save_list();
463 rb->splash(HZ, "Done");
464 return list->count;
467 int start_shuffled_play(void)
469 int *order;
470 size_t max_shuffle_size;
471 int i = 0;
473 /* get memory for shuffling */
474 order=rb->plugin_get_buffer(&max_shuffle_size);
475 max_shuffle_size/=sizeof(int);
476 if (order==NULL || max_shuffle_size==0)
478 rb->splashf(HZ*2, "Not enough memory for shuffling");
479 return 0;
482 /* load the dat file if not already done */
483 if ((list == NULL || list->count == 0) && (i = load_list()) != 0)
485 rb->splashf(HZ*2, "Could not load %s, rv = %d", RFA_FILE, i);
486 return 0;
489 if (list->count <= 0)
491 rb->splashf(HZ*2, "no dirs in list file: %s", RFA_FILE);
492 return 0;
495 /* shuffle the thing */
496 rb->srand(*rb->current_tick);
497 if(list->count>(int)max_shuffle_size)
499 rb->splashf(HZ*2, "Too many folders: %d (room for %d)", list->count,(int)max_shuffle_size);
500 return 0;
502 for(i=0;i<list->count;i++)
503 order[i]=i;
505 for(i = list->count - 1; i >= 0; i--)
507 /* the rand is from 0 to RAND_MAX, so adjust to our value range */
508 int candidate = rb->rand() % (i + 1);
510 /* now swap the values at the 'i' and 'candidate' positions */
511 int store = order[candidate];
512 order[candidate] = order[i];
513 order[i] = store;
516 /* We don't want whatever is playing */
517 if (!(rb->playlist_remove_all_tracks(NULL) == 0
518 && rb->playlist_create(NULL, NULL) == 0))
520 rb->splashf(HZ*2, "Could not clear playlist");
521 return 0;
524 /* add the lot to the playlist */
525 for (i = 0; i < list->count; i++)
527 if (list->folder[order[i]][0] != ' ')
529 rb->playlist_insert_directory(NULL,list->folder[order[i]],PLAYLIST_INSERT_LAST,false,false);
531 if (rb->action_userabort(TIMEOUT_NOBLOCK))
533 break;
536 rb->splash(HZ, "Done");
537 rb->playlist_start(0,0);
538 return 1;
541 enum plugin_status main_menu(void)
543 bool exit = false;
544 MENUITEM_STRINGLIST(menu, "Main Menu", NULL,
545 "Generate Folder List",
546 "Edit Folder List",
547 "Export List To Textfile",
548 "Import List From Textfile",
549 "Play Shuffled",
550 "Quit");
552 while (!exit)
554 switch (rb->do_menu(&menu, NULL, NULL, false))
556 case 0: /* generate */
557 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
558 rb->cpu_boost(true);
559 #endif
560 generate();
561 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
562 rb->cpu_boost(false);
563 #endif
564 #ifdef HAVE_REMOTE_LCD
565 rb->remote_backlight_on();
566 #endif
567 rb->backlight_on();
568 break;
569 case 1:
570 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
571 rb->cpu_boost(true);
572 #endif
573 if (edit_list() < 0)
574 exit = true;
575 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
576 rb->cpu_boost(false);
577 #endif
578 #ifdef HAVE_REMOTE_LCD
579 rb->remote_backlight_on();
580 #endif
581 rb->backlight_on();
582 break;
583 case 2: /* export to textfile */
584 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
585 rb->cpu_boost(true);
586 #endif
587 export_list_to_file_text();
588 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
589 rb->cpu_boost(false);
590 #endif
591 #ifdef HAVE_REMOTE_LCD
592 rb->remote_backlight_on();
593 #endif
594 rb->backlight_on();
595 break;
596 case 3: /* import from textfile */
597 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
598 rb->cpu_boost(true);
599 #endif
600 import_list_from_file_text();
601 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
602 rb->cpu_boost(false);
603 #endif
604 #ifdef HAVE_REMOTE_LCD
605 rb->remote_backlight_on();
606 #endif
607 rb->backlight_on();
608 break;
609 case 4:
610 if (!start_shuffled_play())
611 return PLUGIN_ERROR;
612 else
613 return PLUGIN_GOTO_WPS;
614 case 5:
615 return PLUGIN_OK;
618 return PLUGIN_OK;
621 enum plugin_status plugin_start(const void* parameter)
623 (void)parameter;
625 cancel = false;
627 return main_menu();