Ged rid of uisimulator/common/io.c for android builds.
[maemo-rb.git] / apps / plugins / disktidy.c
blob1e6c1536e2cae31cac9ba92079f1b9e75966f423
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
21 #include "plugin.h"
22 #include "errno.h"
25 static int removed = 0; /* number of items removed */
27 /* function return values */
28 enum tidy_return
30 TIDY_RETURN_OK = 0,
31 TIDY_RETURN_ERROR = 1,
32 TIDY_RETURN_USB = 2,
33 TIDY_RETURN_ABORT = 3,
36 #define MAX_TYPES 64
37 struct tidy_type {
38 char filestring[64];
39 bool directory;
40 bool remove;
41 } tidy_types[MAX_TYPES];
42 int tidy_type_count;
43 bool tidy_loaded_and_changed = false;
45 #define DEFAULT_FILES PLUGIN_APPS_DIR "/disktidy.config"
46 #define CUSTOM_FILES PLUGIN_APPS_DIR "/disktidy_custom.config"
47 void add_item(const char* name, int index)
49 rb->strcpy(tidy_types[index].filestring, name);
50 if (name[rb->strlen(name)-1] == '/')
52 tidy_types[index].directory = true;
53 tidy_types[index].filestring[rb->strlen(name)-1] = '\0';
55 else
56 tidy_types[index].directory = false;
58 static int find_file_string(const char *file, char *last_group)
60 char temp[MAX_PATH];
61 int i = 0, idx_last_group = -1;
62 bool folder = false;
63 rb->strcpy(temp, file);
64 if (temp[rb->strlen(temp)-1] == '/')
66 folder = true;
67 temp[rb->strlen(temp)-1] = '\0';
69 while (i<tidy_type_count)
71 if (!rb->strcmp(tidy_types[i].filestring, temp) &&
72 folder == tidy_types[i].directory)
73 return i;
74 else if (!rb->strcmp(tidy_types[i].filestring, last_group))
75 idx_last_group = i;
76 i++;
78 /* not found, so insert it into its group */
79 if (file[0] != '<' && idx_last_group != -1)
81 for (i=idx_last_group; i<tidy_type_count; i++)
83 if (tidy_types[i].filestring[0] == '<')
85 idx_last_group = i;
86 break;
89 /* shift items up one */
90 for (i=tidy_type_count;i>idx_last_group;i--)
92 rb->strcpy(tidy_types[i].filestring, tidy_types[i-1].filestring);
93 tidy_types[i].directory = tidy_types[i-1].directory;
94 tidy_types[i].remove = tidy_types[i-1].remove;
96 tidy_type_count++;
97 add_item(file, idx_last_group+1);
98 return idx_last_group+1;
100 return i;
103 bool tidy_load_file(const char* file)
105 int fd = rb->open(file, O_RDONLY), i;
106 char buf[MAX_PATH], *str, *remove;
107 char last_group[MAX_PATH] = "";
108 bool new;
109 if (fd < 0)
110 return false;
111 while ((tidy_type_count < MAX_TYPES) &&
112 rb->read_line(fd, buf, MAX_PATH))
114 if (rb->settings_parseline(buf, &str, &remove))
116 i = find_file_string(str, last_group);
117 new = (i >= tidy_type_count);
118 if (!rb->strcmp(remove, "yes"))
119 tidy_types[i].remove = true;
120 else tidy_types[i].remove = false;
121 if (new)
123 i = tidy_type_count;
124 add_item(str, i);
125 tidy_type_count++;
127 if (str[0] == '<')
128 rb->strcpy(last_group, str);
131 rb->close(fd);
132 return true;
135 bool tidy_remove_item(char *item, int attr)
137 int i;
138 char *file;
139 bool ret = false, rem = false;
140 for (i=0; ret == false && i < tidy_type_count; i++)
142 file = tidy_types[i].filestring;
143 if (file[rb->strlen(file)-1] == '*')
145 if (!rb->strncmp(file, item, rb->strlen(file)-1))
146 rem = true;
148 else if (!rb->strcmp(file, item))
149 rem = true;
150 if (rem)
152 if (!tidy_types[i].remove)
153 return false;
154 if (attr&ATTR_DIRECTORY)
155 ret = tidy_types[i].directory;
156 else ret = true;
159 return ret;
162 void tidy_lcd_status(const char *name)
164 /* display status text */
165 rb->lcd_clear_display();
166 rb->lcd_puts(0, 0, "Working ...");
167 rb->lcd_puts(0, 1, name);
168 #ifdef HAVE_LCD_BITMAP
169 rb->lcd_putsf(0, 2, "Cleaned up %d items", removed);
170 #endif
171 rb->lcd_update();
174 int tidy_path_append_entry(char *path, struct dirent *entry, int *path_length)
176 int name_len = rb->strlen(entry->d_name);
177 /* for the special case of path="/" this is one bigger but it's not a problem */
178 int new_length = *path_length + name_len + 1;
180 /* check overflow (keep space for trailing zero) */
181 if(new_length >= MAX_PATH)
182 return 0;
184 /* special case for path <> "/" */
185 if(rb->strcmp(path, "/") != 0)
187 rb->strcat(path + *path_length, "/");
188 (*path_length)++;
190 /* strcat is unsafe but the previous check normally avoid any problem */
191 /* use path_length to optimise */
193 rb->strcat(path + *path_length, entry->d_name);
194 *path_length += name_len;
196 return 1;
199 void tidy_path_remove_entry(char *path, int old_path_length, int *path_length)
201 path[old_path_length] = '\0';
202 *path_length = old_path_length;
205 /* path is assumed to be array of size MAX_PATH */
206 enum tidy_return tidy_removedir(char *path, int *path_length)
208 /* delete directory */
209 struct dirent *entry;
210 enum tidy_return status = TIDY_RETURN_OK;
211 int button;
212 DIR *dir;
213 int old_path_length = *path_length;
215 /* display status text */
216 tidy_lcd_status(path);
218 rb->yield();
220 dir = rb->opendir(path);
221 if (dir)
223 while((status == TIDY_RETURN_OK) && ((entry = rb->readdir(dir)) != 0))
224 /* walk directory */
226 /* check for user input and usb connect */
227 button = rb->get_action(CONTEXT_STD, TIMEOUT_NOBLOCK);
228 if (button == ACTION_STD_CANCEL)
230 rb->closedir(dir);
231 return TIDY_RETURN_ABORT;
233 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
235 rb->closedir(dir);
236 return TIDY_RETURN_USB;
239 rb->yield();
241 /* get absolute path */
242 /* returns an error if path is too long */
243 if(!tidy_path_append_entry(path, entry, path_length))
244 /* silent error */
245 continue;
248 struct dirinfo info = rb->dir_get_info(dir, entry);
249 if (info.attribute & ATTR_DIRECTORY)
251 /* dir ignore "." and ".." */
252 if ((rb->strcmp(entry->d_name, ".") != 0) && \
253 (rb->strcmp(entry->d_name, "..") != 0))
255 tidy_removedir(path, path_length);
258 else
260 /* file */
261 removed++;
262 rb->remove(path);
265 /* restore path */
266 tidy_path_remove_entry(path, old_path_length, path_length);
268 rb->closedir(dir);
269 /* rmdir */
270 removed++;
271 rb->rmdir(path);
273 else
275 status = TIDY_RETURN_ERROR;
277 return status;
280 /* path is assumed to be array of size MAX_PATH */
281 enum tidy_return tidy_clean(char *path, int *path_length)
283 /* deletes junk files and dirs left by system */
284 struct dirent *entry;
285 enum tidy_return status = TIDY_RETURN_OK;
286 int button;
287 int del; /* has the item been deleted */
288 DIR *dir;
289 int old_path_length = *path_length;
291 /* display status text */
292 tidy_lcd_status(path);
294 rb->yield();
296 dir = rb->opendir(path);
297 if (dir)
299 while((status == TIDY_RETURN_OK) && ((entry = rb->readdir(dir)) != 0))
300 /* walk directory */
302 struct dirinfo info = rb->dir_get_info(dir, entry);
303 /* check for user input and usb connect */
304 button = rb->get_action(CONTEXT_STD, TIMEOUT_NOBLOCK);
305 if (button == ACTION_STD_CANCEL)
307 rb->closedir(dir);
308 return TIDY_RETURN_ABORT;
310 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
312 rb->closedir(dir);
313 return TIDY_RETURN_USB;
316 rb->yield();
318 if (info.attribute & ATTR_DIRECTORY)
320 /* directory ignore "." and ".." */
321 if ((rb->strcmp(entry->d_name, ".") != 0) && \
322 (rb->strcmp(entry->d_name, "..") != 0))
324 del = 0;
326 /* get absolute path */
327 /* returns an error if path is too long */
328 if(!tidy_path_append_entry(path, entry, path_length))
329 /* silent error */
330 continue;
332 if (tidy_remove_item(entry->d_name, info.attribute))
334 /* delete dir */
335 tidy_removedir(path, path_length);
336 del = 1;
339 if (del == 0)
341 /* dir not deleted so clean it */
342 status = tidy_clean(path, path_length);
345 /* restore path */
346 tidy_path_remove_entry(path, old_path_length, path_length);
349 else
351 /* file */
352 del = 0;
353 if (tidy_remove_item(entry->d_name, info.attribute))
355 /* get absolute path */
356 /* returns an error if path is too long */
357 if(!tidy_path_append_entry(path, entry, path_length))
358 /* silent error */
359 continue;
361 removed++; /* increment removed files counter */
362 /* delete file */
363 rb->remove(path);
364 del = 1;
366 /* restore path */
367 tidy_path_remove_entry(path, old_path_length, path_length);
371 rb->closedir(dir);
372 return status;
374 else
376 return TIDY_RETURN_ERROR;
380 enum tidy_return tidy_do(void)
382 /* clean disk and display num of items removed */
383 enum tidy_return status;
384 char path[MAX_PATH];
385 int path_length;
387 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
388 rb->cpu_boost(true);
389 #endif
391 rb->strcpy(path, "/");
392 path_length = rb->strlen(path);
393 status = tidy_clean(path, &path_length);
395 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
396 rb->cpu_boost(false);
397 #endif
399 if ((status == TIDY_RETURN_OK) || (status == TIDY_RETURN_ABORT))
401 rb->lcd_clear_display();
402 if (status == TIDY_RETURN_ABORT)
404 rb->splash(HZ, "User aborted");
405 rb->lcd_clear_display();
407 rb->splashf(HZ*2, "Cleaned up %d items", removed);
409 return status;
412 enum themable_icons get_icon(int item, void * data)
414 (void)data;
415 if (tidy_types[item].filestring[0] == '<') /* special type */
416 return Icon_Folder;
417 else if (tidy_types[item].remove)
418 return Icon_Cursor;
419 else
420 return Icon_NOICON;
423 static const char* get_name(int selected_item, void * data,
424 char * buffer, size_t buffer_len)
426 (void)data;
427 if (tidy_types[selected_item].directory)
429 rb->snprintf(buffer, buffer_len, "%s/",
430 tidy_types[selected_item].filestring);
431 return buffer;
433 return tidy_types[selected_item].filestring;
436 int list_action_callback(int action, struct gui_synclist *lists)
438 if (action == ACTION_STD_OK)
440 int selection = rb->gui_synclist_get_sel_pos(lists);
441 if (tidy_types[selection].filestring[0] == '<')
443 int i;
444 if (!rb->strcmp(tidy_types[selection].filestring, "< ALL >"))
446 for (i=0; i<tidy_type_count; i++)
448 if (tidy_types[i].filestring[0] != '<')
449 tidy_types[i].remove = true;
452 else if (!rb->strcmp(tidy_types[selection].filestring, "< NONE >"))
454 for (i=0; i<tidy_type_count; i++)
456 if (tidy_types[i].filestring[0] != '<')
457 tidy_types[i].remove = false;
460 else /* toggle all untill the next <> */
462 selection++;
463 while (selection < tidy_type_count &&
464 tidy_types[selection].filestring[0] != '<')
466 tidy_types[selection].remove = !tidy_types[selection].remove;
467 selection++;
471 else
472 tidy_types[selection].remove = !tidy_types[selection].remove;
473 tidy_loaded_and_changed = true;
474 return ACTION_REDRAW;
476 return action;
479 enum tidy_return tidy_lcd_menu(void)
481 int selection = 0;
482 enum tidy_return status = TIDY_RETURN_OK;
483 bool menu_quit = false;
485 MENUITEM_STRINGLIST(menu, "Disktidy Menu", NULL,
486 "Start Cleaning", "Files to Clean",
487 "Quit");
489 while (!menu_quit)
491 switch(rb->do_menu(&menu, &selection, NULL, false))
493 case 0:
494 menu_quit = true; /* start cleaning */
495 break;
497 case 1:
499 bool show_icons = rb->global_settings->show_icons;
500 struct simplelist_info list;
501 rb->simplelist_info_init(&list, "Files to Clean",
502 tidy_type_count, NULL);
503 list.get_icon = get_icon;
504 list.get_name = get_name;
505 list.action_callback = list_action_callback;
506 rb->simplelist_show_list(&list);
507 rb->global_settings->show_icons = show_icons;
509 break;
511 default:
512 status = TIDY_RETURN_ABORT; /* exit plugin */
513 menu_quit = true;
514 break;
517 return status;
520 /* this is the plugin entry point */
521 enum plugin_status plugin_start(const void* parameter)
523 enum tidy_return status;
524 (void)parameter;
526 tidy_type_count = 0;
527 tidy_load_file(DEFAULT_FILES);
528 tidy_load_file(CUSTOM_FILES);
529 if (tidy_type_count == 0)
531 rb->splash(3*HZ, "Missing disktidy.config file");
532 return PLUGIN_ERROR;
534 status = tidy_lcd_menu();
535 if (tidy_loaded_and_changed)
537 int fd = rb->creat(CUSTOM_FILES, 0666);
538 int i;
539 if (fd >= 0)
541 for(i=0;i<tidy_type_count;i++)
543 rb->fdprintf(fd, "%s%c: %s\n", tidy_types[i].filestring,
544 tidy_types[i].directory?'/':'\0',
545 tidy_types[i].remove?"yes":"no");
547 rb->close(fd);
550 if (status == TIDY_RETURN_ABORT)
551 return PLUGIN_OK;
552 while (true)
554 status = tidy_do();
556 switch (status)
558 case TIDY_RETURN_OK:
559 return PLUGIN_OK;
560 case TIDY_RETURN_ERROR:
561 return PLUGIN_ERROR;
562 case TIDY_RETURN_USB:
563 return PLUGIN_USB_CONNECTED;
564 case TIDY_RETURN_ABORT:
565 return PLUGIN_OK;
569 if (rb->default_event_handler(rb->button_get(false)) == SYS_USB_CONNECTED)
570 return PLUGIN_USB_CONNECTED;
572 rb->yield();
574 return PLUGIN_OK;