1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 David Dent
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 ****************************************************************************/
25 static int removed
= 0; /* number of items removed */
27 /* function return values */
31 TIDY_RETURN_ERROR
= 1,
33 TIDY_RETURN_ABORT
= 3,
43 } tidy_types
[MAX_TYPES
];
45 bool tidy_loaded_and_changed
= false;
47 #define DEFAULT_FILES PLUGIN_APPS_DIR "/disktidy.config"
48 #define CUSTOM_FILES PLUGIN_APPS_DIR "/disktidy_custom.config"
49 void add_item(const char* name
, int index
)
52 rb
->strcpy(tidy_types
[index
].filestring
, name
);
53 if (name
[rb
->strlen(name
)-1] == '/')
55 tidy_types
[index
].directory
= true;
56 tidy_types
[index
].filestring
[rb
->strlen(name
)-1] = '\0';
59 tidy_types
[index
].directory
= false;
60 a
= rb
->strchr(name
, '*');
63 tidy_types
[index
].pre
= a
- name
;
64 tidy_types
[index
].post
= rb
->strlen(a
+1);
68 tidy_types
[index
].pre
= -1;
69 tidy_types
[index
].post
= -1;
72 static int find_file_string(const char *file
, char *last_group
)
75 int i
= 0, idx_last_group
= -1;
77 rb
->strcpy(temp
, file
);
78 if (temp
[rb
->strlen(temp
)-1] == '/')
81 temp
[rb
->strlen(temp
)-1] = '\0';
83 while (i
<tidy_type_count
)
85 if (!rb
->strcmp(tidy_types
[i
].filestring
, temp
) &&
86 folder
== tidy_types
[i
].directory
)
88 else if (!rb
->strcmp(tidy_types
[i
].filestring
, last_group
))
92 /* not found, so insert it into its group */
93 if (file
[0] != '<' && idx_last_group
!= -1)
95 for (i
=idx_last_group
; i
<tidy_type_count
; i
++)
97 if (tidy_types
[i
].filestring
[0] == '<')
103 /* shift items up one */
104 for (i
=tidy_type_count
;i
>idx_last_group
;i
--)
106 rb
->memcpy(&tidy_types
[i
], &tidy_types
[i
-1], sizeof(struct tidy_type
));
109 add_item(file
, idx_last_group
+1);
110 return idx_last_group
+1;
115 bool tidy_load_file(const char* file
)
117 int fd
= rb
->open(file
, O_RDONLY
), i
;
118 char buf
[MAX_PATH
], *str
, *remove
;
119 char last_group
[MAX_PATH
] = "";
123 while ((tidy_type_count
< MAX_TYPES
) &&
124 rb
->read_line(fd
, buf
, MAX_PATH
))
126 if (rb
->settings_parseline(buf
, &str
, &remove
))
128 i
= find_file_string(str
, last_group
);
129 new = (i
>= tidy_type_count
);
130 if (!rb
->strcmp(remove
, "yes"))
131 tidy_types
[i
].remove
= true;
132 else tidy_types
[i
].remove
= false;
140 rb
->strcpy(last_group
, str
);
147 static bool match(struct tidy_type
*tidy_type
, char *string
, int len
)
149 char *pattern
= tidy_type
->filestring
;
150 if (tidy_type
->pre
< 0)
152 /* no '*', just compare. */
153 return (rb
->strcmp(pattern
, string
) == 0);
155 /* pattern is too long for the string. avoid 'ab*bc' matching 'abc'. */
156 if (len
< tidy_type
->pre
+ tidy_type
->post
)
158 /* pattern has '*', compare former part of '*' to the begining of
159 the string and compare next part of '*' to the end of string. */
160 return (rb
->strncmp(pattern
, string
, tidy_type
->pre
) == 0 &&
161 rb
->strcmp(pattern
+ tidy_type
->pre
+ 1,
162 string
+ len
- tidy_type
->post
) == 0);
165 bool tidy_remove_item(char *item
, int attr
)
170 len
= rb
->strlen(item
);
171 for (i
=0; ret
== false && i
< tidy_type_count
; i
++)
173 if (match(&tidy_types
[i
], item
, len
))
175 if (!tidy_types
[i
].remove
)
177 if (attr
&ATTR_DIRECTORY
)
178 ret
= tidy_types
[i
].directory
;
185 void tidy_lcd_status(const char *name
)
187 /* display status text */
188 rb
->lcd_clear_display();
189 rb
->lcd_puts(0, 0, "Working ...");
190 rb
->lcd_puts(0, 1, name
);
191 #ifdef HAVE_LCD_BITMAP
192 rb
->lcd_putsf(0, 2, "Cleaned up %d items", removed
);
197 int tidy_path_append_entry(char *path
, struct dirent
*entry
, int *path_length
)
199 int name_len
= rb
->strlen(entry
->d_name
);
200 /* for the special case of path="/" this is one bigger but it's not a problem */
201 int new_length
= *path_length
+ name_len
+ 1;
203 /* check overflow (keep space for trailing zero) */
204 if(new_length
>= MAX_PATH
)
207 /* special case for path <> "/" */
208 if(rb
->strcmp(path
, "/") != 0)
210 rb
->strcat(path
+ *path_length
, "/");
213 /* strcat is unsafe but the previous check normally avoid any problem */
214 /* use path_length to optimise */
216 rb
->strcat(path
+ *path_length
, entry
->d_name
);
217 *path_length
+= name_len
;
222 void tidy_path_remove_entry(char *path
, int old_path_length
, int *path_length
)
224 path
[old_path_length
] = '\0';
225 *path_length
= old_path_length
;
228 /* path is assumed to be array of size MAX_PATH */
229 enum tidy_return
tidy_removedir(char *path
, int *path_length
)
231 /* delete directory */
232 struct dirent
*entry
;
233 enum tidy_return status
= TIDY_RETURN_OK
;
236 int old_path_length
= *path_length
;
238 /* display status text */
239 tidy_lcd_status(path
);
243 dir
= rb
->opendir(path
);
246 while((status
== TIDY_RETURN_OK
) && ((entry
= rb
->readdir(dir
)) != 0))
249 /* check for user input and usb connect */
250 button
= rb
->get_action(CONTEXT_STD
, TIMEOUT_NOBLOCK
);
251 if (button
== ACTION_STD_CANCEL
)
254 return TIDY_RETURN_ABORT
;
256 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
259 return TIDY_RETURN_USB
;
264 /* get absolute path */
265 /* returns an error if path is too long */
266 if(!tidy_path_append_entry(path
, entry
, path_length
))
270 struct dirinfo info
= rb
->dir_get_info(dir
, entry
);
271 if (info
.attribute
& ATTR_DIRECTORY
)
273 /* dir ignore "." and ".." */
274 if ((rb
->strcmp(entry
->d_name
, ".") != 0) && \
275 (rb
->strcmp(entry
->d_name
, "..") != 0))
277 status
= tidy_removedir(path
, path_length
);
288 tidy_path_remove_entry(path
, old_path_length
, path_length
);
297 status
= TIDY_RETURN_ERROR
;
302 /* path is assumed to be array of size MAX_PATH */
303 enum tidy_return
tidy_clean(char *path
, int *path_length
)
305 /* deletes junk files and dirs left by system */
306 struct dirent
*entry
;
307 enum tidy_return status
= TIDY_RETURN_OK
;
310 int old_path_length
= *path_length
;
312 /* display status text */
313 tidy_lcd_status(path
);
317 dir
= rb
->opendir(path
);
320 while((status
== TIDY_RETURN_OK
) && ((entry
= rb
->readdir(dir
)) != 0))
323 struct dirinfo info
= rb
->dir_get_info(dir
, entry
);
324 /* check for user input and usb connect */
325 button
= rb
->get_action(CONTEXT_STD
, TIMEOUT_NOBLOCK
);
326 if (button
== ACTION_STD_CANCEL
)
329 return TIDY_RETURN_ABORT
;
331 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
334 return TIDY_RETURN_USB
;
339 if (info
.attribute
& ATTR_DIRECTORY
)
341 /* directory ignore "." and ".." */
342 if ((rb
->strcmp(entry
->d_name
, ".") != 0) && \
343 (rb
->strcmp(entry
->d_name
, "..") != 0))
345 /* get absolute path */
346 /* returns an error if path is too long */
347 if(!tidy_path_append_entry(path
, entry
, path_length
))
351 if (tidy_remove_item(entry
->d_name
, info
.attribute
))
354 status
= tidy_removedir(path
, path_length
);
358 /* dir not deleted so clean it */
359 status
= tidy_clean(path
, path_length
);
363 tidy_path_remove_entry(path
, old_path_length
, path_length
);
369 if (tidy_remove_item(entry
->d_name
, info
.attribute
))
371 /* get absolute path */
372 /* returns an error if path is too long */
373 if(!tidy_path_append_entry(path
, entry
, path_length
))
377 removed
++; /* increment removed files counter */
382 tidy_path_remove_entry(path
, old_path_length
, path_length
);
391 return TIDY_RETURN_ERROR
;
395 enum tidy_return
tidy_do(void)
397 /* clean disk and display num of items removed */
398 enum tidy_return status
;
402 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
406 rb
->strcpy(path
, "/");
407 path_length
= rb
->strlen(path
);
408 status
= tidy_clean(path
, &path_length
);
410 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
411 rb
->cpu_boost(false);
414 if ((status
== TIDY_RETURN_OK
) || (status
== TIDY_RETURN_ABORT
))
416 rb
->lcd_clear_display();
417 if (status
== TIDY_RETURN_ABORT
)
419 rb
->splash(HZ
, "User aborted");
420 rb
->lcd_clear_display();
422 rb
->splashf(HZ
*2, "Cleaned up %d items", removed
);
427 enum themable_icons
get_icon(int item
, void * data
)
430 if (tidy_types
[item
].filestring
[0] == '<') /* special type */
432 else if (tidy_types
[item
].remove
)
438 static const char* get_name(int selected_item
, void * data
,
439 char * buffer
, size_t buffer_len
)
442 if (tidy_types
[selected_item
].directory
)
444 rb
->snprintf(buffer
, buffer_len
, "%s/",
445 tidy_types
[selected_item
].filestring
);
448 return tidy_types
[selected_item
].filestring
;
451 int list_action_callback(int action
, struct gui_synclist
*lists
)
453 if (action
== ACTION_STD_OK
)
455 int selection
= rb
->gui_synclist_get_sel_pos(lists
);
456 if (tidy_types
[selection
].filestring
[0] == '<')
459 if (!rb
->strcmp(tidy_types
[selection
].filestring
, "< ALL >"))
461 for (i
=0; i
<tidy_type_count
; i
++)
463 if (tidy_types
[i
].filestring
[0] != '<')
464 tidy_types
[i
].remove
= true;
467 else if (!rb
->strcmp(tidy_types
[selection
].filestring
, "< NONE >"))
469 for (i
=0; i
<tidy_type_count
; i
++)
471 if (tidy_types
[i
].filestring
[0] != '<')
472 tidy_types
[i
].remove
= false;
475 else /* toggle all untill the next <> */
478 while (selection
< tidy_type_count
&&
479 tidy_types
[selection
].filestring
[0] != '<')
481 tidy_types
[selection
].remove
= !tidy_types
[selection
].remove
;
487 tidy_types
[selection
].remove
= !tidy_types
[selection
].remove
;
488 tidy_loaded_and_changed
= true;
489 return ACTION_REDRAW
;
494 enum tidy_return
tidy_lcd_menu(void)
497 enum tidy_return status
= TIDY_RETURN_OK
;
498 bool menu_quit
= false;
500 MENUITEM_STRINGLIST(menu
, "Disktidy Menu", NULL
,
501 "Start Cleaning", "Files to Clean",
506 switch(rb
->do_menu(&menu
, &selection
, NULL
, false))
509 menu_quit
= true; /* start cleaning */
514 struct simplelist_info list
;
515 rb
->simplelist_info_init(&list
, "Files to Clean",
516 tidy_type_count
, NULL
);
517 list
.get_icon
= get_icon
;
518 list
.get_name
= get_name
;
519 list
.action_callback
= list_action_callback
;
520 rb
->simplelist_show_list(&list
);
525 status
= TIDY_RETURN_ABORT
; /* exit plugin */
533 /* this is the plugin entry point */
534 enum plugin_status
plugin_start(const void* parameter
)
536 enum tidy_return status
;
540 tidy_load_file(DEFAULT_FILES
);
541 tidy_load_file(CUSTOM_FILES
);
542 if (tidy_type_count
== 0)
544 rb
->splash(3*HZ
, "Missing disktidy.config file");
547 status
= tidy_lcd_menu();
548 if (tidy_loaded_and_changed
)
550 int fd
= rb
->creat(CUSTOM_FILES
, 0666);
554 for(i
=0;i
<tidy_type_count
;i
++)
556 rb
->fdprintf(fd
, "%s%c: %s\n", tidy_types
[i
].filestring
,
557 tidy_types
[i
].directory
?'/':'\0',
558 tidy_types
[i
].remove
?"yes":"no");
563 if (status
== TIDY_RETURN_ABORT
)
573 case TIDY_RETURN_ERROR
:
575 case TIDY_RETURN_USB
:
576 return PLUGIN_USB_CONNECTED
;
577 case TIDY_RETURN_ABORT
:
582 if (rb
->default_event_handler(rb
->button_get(false)) == SYS_USB_CONNECTED
)
583 return PLUGIN_USB_CONNECTED
;