diff options
Diffstat (limited to 'libmenu/menu_filesel.c')
-rw-r--r-- | libmenu/menu_filesel.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/libmenu/menu_filesel.c b/libmenu/menu_filesel.c new file mode 100644 index 0000000000..83eaa34881 --- /dev/null +++ b/libmenu/menu_filesel.c @@ -0,0 +1,283 @@ + +#include <stdlib.h> +#include <stdio.h> +#include <dirent.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <unistd.h> + + +#include "../config.h" + +#include "../m_struct.h" +#include "../m_option.h" + +#include "img_format.h" +#include "mp_image.h" + +#include "menu.h" +#include "menu_list.h" +#include "../input/input.h" +#include "../linux/keycodes.h" + +struct list_entry_s { + struct list_entry p; + int d; +}; + +struct menu_priv_s { + menu_list_priv_t p; + char* dir; // current dir + /// Cfg fields + char* path; + char* title; + char* file_action; + char* dir_action; + int auto_close; +}; + +static struct menu_priv_s cfg_dflt = { + MENU_LIST_PRIV_DFLT, + NULL, + + NULL, + "Select a file: %p", + "loadfile %p", + NULL, + 0 +}; + +#define ST_OFF(m) M_ST_OFF(struct menu_priv_s,m) + +static m_option_t cfg_fields[] = { + MENU_LIST_PRIV_FIELDS, + { "path", ST_OFF(path), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "title", ST_OFF(title), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "file-action", ST_OFF(file_action), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "dir-action", ST_OFF(dir_action), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "auto-close", ST_OFF(auto_close), CONF_TYPE_FLAG, 0, 0, 1, NULL }, + { NULL, NULL, NULL, 0,0,0,NULL } +}; + +#define mpriv (menu->priv) + +static void free_entry(list_entry_t* entry) { + free(entry->p.txt); + free(entry); +} + +static char* replace_path(char* title , char* dir) { + char *p = strstr(title,"%p"); + if(p) { + int tl = strlen(title); + int dl = strlen(dir); + int t1l = p-title; + int l = tl - 2 + dl; + char*r = malloc(l + 1); + memcpy(r,title,t1l); + memcpy(r+t1l,dir,dl); + if(tl - t1l - 2 > 0) + memcpy(r+t1l+dl,p+2,tl - t1l - 2); + r[l] = '\0'; + return r; + } else + return title; +} + +typedef int (*kill_warn)(const void*, const void*); + +static int open_dir(menu_t* menu,char* args) { + struct dirent **namelist; + struct stat st; + int n; + char* p = NULL; + list_entry_t* e; + + int mylstat(char *dir, char *file,struct stat* st) { + int l = strlen(dir) + strlen(file); + char s[l+1]; + sprintf(s,"%s%s",args,file); + return lstat(s,st); + } + + int compare(struct dirent **a,struct dirent **b) { + struct stat as,bs; + mylstat(args,(*a)->d_name,&as); + mylstat(args,(*b)->d_name,&bs); + if(S_ISDIR(as.st_mode)) { + if(S_ISDIR(bs.st_mode)) + return alphasort(b,a); + else + return 1; + } else { + if(S_ISDIR(bs.st_mode)) + return -1; + else + return alphasort(b,a); + } + } + + int select_f(const struct dirent *d) { + if(d->d_name[0] != '.' || strcmp(d->d_name,"..") == 0) + return 1; + return 0; + } + + menu_list_init(menu); + + if(mpriv->dir) + free(mpriv->dir); + mpriv->dir = strdup(args); + if(mpriv->p.title && mpriv->p.title != mpriv->title && mpriv->p.title != cfg_dflt.p.title) + free(mpriv->p.title); + p = strstr(mpriv->title,"%p"); + + mpriv->p.title = replace_path(mpriv->title,mpriv->dir); + + n = scandir(mpriv->dir, &namelist, select_f, (kill_warn)compare); + if (n < 0) { + printf("scandir error: %s\n",strerror(errno)); + return 0; + } + while(n--) { + e = calloc(1,sizeof(list_entry_t)); + mylstat(args,namelist[n]->d_name,&st); + + if(S_ISDIR(st.st_mode)) { + int sl =strlen(namelist[n]->d_name); + e->p.txt = malloc(sl + 2); + strncpy(e->p.txt,namelist[n]->d_name,sl); + e->p.txt[sl] = '/'; + e->p.txt[sl+1] = '\0'; + e->d = 1; + menu_list_add_entry(menu,e); + } else if(strcmp(namelist[n]->d_name,"..") == 0 || namelist[n]->d_name[0] != '.') { + e->p.txt = strdup(namelist[n]->d_name); + menu_list_add_entry(menu,e); + } + free(namelist[n]); + } + free(namelist); + + return 1; +} + + +static void read_cmd(menu_t* menu,int cmd) { + mp_cmd_t* c = NULL; + switch(cmd) { + case MENU_CMD_OK: { + // Directory + if(mpriv->p.current->d) { + if(mpriv->dir_action) { + int fname_len = strlen(mpriv->dir) + strlen(mpriv->p.current->p.txt) + 1; + char filename[fname_len]; + char* str; + sprintf(filename,"%s%s",mpriv->dir,mpriv->p.current->p.txt); + str = replace_path(mpriv->dir_action,filename); + c = mp_input_parse_cmd(str); + if(str != mpriv->dir_action) + free(str); + } else { // Default action : open this dirctory ourself + int l = strlen(mpriv->dir); + char *slash = NULL, *p = NULL; + if(strcmp(mpriv->p.current->p.txt,"../") == 0) { + if(l <= 1) break; + mpriv->dir[l-1] = '\0'; + slash = strrchr(mpriv->dir,'/'); + if(!slash) break; + slash[1] = '\0'; + p = strdup(mpriv->dir); + } else { + p = malloc(l + strlen(mpriv->p.current->p.txt) + 1); + sprintf(p,"%s%s",mpriv->dir,mpriv->p.current->p.txt); + } + menu_list_uninit(menu,free_entry); + if(!open_dir(menu,p)) { + printf("Can't open directory %s\n",p); + menu->cl = 1; + } + free(p); + } + } else { // Files + int fname_len = strlen(mpriv->dir) + strlen(mpriv->p.current->p.txt) + 1; + char filename[fname_len]; + char *str; + sprintf(filename,"%s%s",mpriv->dir,mpriv->p.current->p.txt); + str = replace_path(mpriv->file_action,filename); + c = mp_input_parse_cmd(str); + if(str != mpriv->file_action) + free(str); + } + if(c) { + mp_input_queue_cmd(c); + if(mpriv->auto_close) + menu->cl = 1; + } + } break; + default: + menu_list_read_cmd(menu,cmd); + } +} + +static void read_key(menu_t* menu,int c){ + if(c == KEY_BS) { + mpriv->p.current = mpriv->p.menu; // Hack : we consider that the first entry is ../ + read_cmd(menu,MENU_CMD_OK); + } else + menu_list_read_key(menu,c,1); +} + +static void clos(menu_t* menu) { + menu_list_uninit(menu,free_entry); + free(mpriv->dir); +} + +static int open_fs(menu_t* menu, char* args) { + char *path = mpriv->path; + int r = 0; + char wd[PATH_MAX+1]; + args = NULL; // Warning kill + + menu->draw = menu_list_draw; + menu->read_cmd = read_cmd; + menu->read_key = read_key; + menu->close = clos; + + getcwd(wd,PATH_MAX); + if(!path || path[0] == '\0') { + int l = strlen(wd) + 2; + char b[l]; + sprintf(b,"%s/",wd); + r = open_dir(menu,b); + } else if(path[0] != '/') { + int al = strlen(path); + int l = strlen(wd) + al + 3; + char b[l]; + if(b[al-1] != '/') + sprintf(b,"%s/%s/",wd,path); + else + sprintf(b,"%s/%s",wd,path); + r = open_dir(menu,b); + } else + r = open_dir(menu,path); + + return r; +} + +const menu_info_t menu_info_filesel = { + "File seletor menu", + "filesel", + "Albeu", + "", + { + "fs_cfg", + sizeof(struct menu_priv_s), + &cfg_dflt, + cfg_fields + }, + open_fs +}; |