document lavc's 'level' option
[mplayer/glamo.git] / libmenu / menu_filesel.c
blob90d77f0c717376566b461242dafe524b98632c3b
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <dirent.h>
5 #include <errno.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <ctype.h>
10 #include <unistd.h>
11 #include <limits.h>
14 #include "config.h"
15 #include "mp_msg.h"
16 #include "help_mp.h"
18 #include "m_struct.h"
19 #include "m_option.h"
21 #include "libmpcodecs/img_format.h"
22 #include "libmpcodecs/mp_image.h"
24 #include "menu.h"
25 #include "menu_list.h"
26 #include "input/input.h"
27 #include "osdep/keycodes.h"
29 struct list_entry_s {
30 struct list_entry p;
31 int d;
34 struct menu_priv_s {
35 menu_list_priv_t p;
36 char* dir; // current dir
37 /// Cfg fields
38 char* path;
39 char* title;
40 char* file_action;
41 char* dir_action;
42 int auto_close;
43 char** actions;
44 char* filter;
47 static struct menu_priv_s cfg_dflt = {
48 MENU_LIST_PRIV_DFLT,
49 NULL,
51 NULL,
52 "Select a file: %p",
53 "loadfile '%p'",
54 NULL,
56 NULL,
57 NULL
60 #define ST_OFF(m) M_ST_OFF(struct menu_priv_s,m)
62 static m_option_t cfg_fields[] = {
63 MENU_LIST_PRIV_FIELDS,
64 { "path", ST_OFF(path), CONF_TYPE_STRING, 0, 0, 0, NULL },
65 { "title", ST_OFF(title), CONF_TYPE_STRING, 0, 0, 0, NULL },
66 { "file-action", ST_OFF(file_action), CONF_TYPE_STRING, 0, 0, 0, NULL },
67 { "dir-action", ST_OFF(dir_action), CONF_TYPE_STRING, 0, 0, 0, NULL },
68 { "auto-close", ST_OFF(auto_close), CONF_TYPE_FLAG, 0, 0, 1, NULL },
69 { "actions", ST_OFF(actions), CONF_TYPE_STRING_LIST, 0, 0, 0, NULL},
70 { "filter", ST_OFF(filter), CONF_TYPE_STRING, 0, 0, 0, NULL},
71 { NULL, NULL, NULL, 0,0,0,NULL }
74 #define mpriv (menu->priv)
76 static void free_entry(list_entry_t* entry) {
77 free(entry->p.txt);
78 free(entry);
81 static char* replace_path(char* title , char* dir) {
82 char *p = strstr(title,"%p");
83 if(p) {
84 int tl = strlen(title);
85 int dl = strlen(dir);
86 int t1l = p-title;
87 int l = tl - 2 + dl;
88 char *r, *n, *d = dir;
89 char term = *(p-1);
91 do {
92 if (*d == '\\' || *d == term)
93 l++;
94 } while (*d++);
95 r = malloc(l + 1);
96 n = r + t1l;
97 memcpy(r,title,t1l);
98 do {
99 if (*dir == '\\' || *dir == term)
100 *n++ = '\\';
101 } while ((*n++ = *dir++));
102 if(tl - t1l - 2 > 0)
103 strcpy(n-1,p+2);
104 return r;
105 } else
106 return title;
109 typedef int (*kill_warn)(const void*, const void*);
111 static int mylstat(char *dir, char *file,struct stat* st) {
112 int l = strlen(dir) + strlen(file);
113 char s[l+2];
114 sprintf(s,"%s/%s",dir,file);
115 return stat(s,st);
118 static int compare(char **a, char **b){
119 if((*a)[strlen(*a) - 1] == '/') {
120 if((*b)[strlen(*b) - 1] == '/')
121 return strcmp(*b, *a) ;
122 else
123 return 1;
124 } else {
125 if((*b)[strlen(*b) - 1] == '/')
126 return -1;
127 else
128 return strcmp(*b, *a);
132 static char **get_extensions(menu_t *menu){
133 char **extensions, ext[32];
134 FILE *fp;
135 int n = 1;
137 if (!mpriv->filter)
138 return NULL;
140 fp = fopen(mpriv->filter, "r");
141 if(!fp)
142 return NULL;
144 extensions = (char **) malloc(sizeof(*extensions));
145 *extensions = NULL;
147 while(fgets(ext,sizeof(ext),fp)) {
148 char **l, *e;
149 int s = strlen (ext);
151 if(ext[s-1] == '\n') {
152 ext[s-1] = '\0';
153 s--;
155 e = (char *) malloc(s+1);
156 extensions = (char **) realloc(extensions, ++n * sizeof(*extensions));
157 extensions = (char **) realloc(extensions, ++n * sizeof(*extensions));
158 strcpy (e, ext);
159 for (l=extensions; *l; l++);
160 *l++ = e;
161 *l = NULL;
164 fclose (fp);
165 return extensions;
168 static void free_extensions(char **extensions){
169 if (extensions) {
170 char **l = extensions;
171 while (*l)
172 free (*l++);
173 free (extensions);
177 static int open_dir(menu_t* menu,char* args) {
178 char **namelist, **tp;
179 struct dirent *dp;
180 struct stat st;
181 int n;
182 char* p = NULL;
183 list_entry_t* e;
184 DIR* dirp;
185 extern int file_filter;
186 char **extensions, **elem, *ext;
188 menu_list_init(menu);
190 if(mpriv->dir)
191 free(mpriv->dir);
192 mpriv->dir = strdup(args);
193 if(mpriv->p.title && mpriv->p.title != mpriv->title && mpriv->p.title != cfg_dflt.p.title)
194 free(mpriv->p.title);
195 p = strstr(mpriv->title,"%p");
197 mpriv->p.title = replace_path(mpriv->title,mpriv->dir);
199 if ((dirp = opendir (mpriv->dir)) == NULL){
200 mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_OpendirError, strerror(errno));
201 return 0;
204 namelist = (char **) malloc(sizeof(char *));
205 extensions = get_extensions(menu);
207 n=0;
208 while ((dp = readdir(dirp)) != NULL) {
209 if(dp->d_name[0] == '.' && strcmp(dp->d_name,"..") != 0)
210 continue;
211 mylstat(args,dp->d_name,&st);
212 if (file_filter && extensions && !S_ISDIR(st.st_mode)) {
213 if((ext = strrchr(dp->d_name,'.')) == NULL)
214 continue;
215 ext++;
216 elem = extensions;
217 do {
218 if (!strcasecmp(ext, *elem))
219 break;
220 } while (*++elem);
221 if (*elem == NULL)
222 continue;
224 if(n%20 == 0){ // Get some more mem
225 if((tp = (char **) realloc(namelist, (n+20) * sizeof (char *)))
226 == NULL) {
227 mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_ReallocError, strerror(errno));
228 n--;
229 goto bailout;
231 namelist=tp;
234 namelist[n] = (char *) malloc(strlen(dp->d_name) + 2);
235 if(namelist[n] == NULL){
236 mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_MallocError, strerror(errno));
237 n--;
238 goto bailout;
241 strcpy(namelist[n], dp->d_name);
242 if(S_ISDIR(st.st_mode))
243 strcat(namelist[n], "/");
244 n++;
247 bailout:
248 free_extensions (extensions);
249 closedir(dirp);
251 qsort(namelist, n, sizeof(char *), (kill_warn)compare);
253 if (n < 0) {
254 mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_ReaddirError,strerror(errno));
255 return 0;
257 while(n--) {
258 if((e = calloc(1,sizeof(list_entry_t))) != NULL){
259 e->p.next = NULL;
260 e->p.txt = strdup(namelist[n]);
261 if(strchr(namelist[n], '/') != NULL)
262 e->d = 1;
263 menu_list_add_entry(menu,e);
264 }else{
265 mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_MallocError, strerror(errno));
267 free(namelist[n]);
269 free(namelist);
271 return 1;
275 static char *action;
277 static void read_cmd(menu_t* menu,int cmd) {
278 mp_cmd_t* c = NULL;
279 switch(cmd) {
280 case MENU_CMD_LEFT:
281 mpriv->p.current = mpriv->p.menu; // Hack : we consider that the first entry is ../
282 case MENU_CMD_RIGHT:
283 case MENU_CMD_OK: {
284 // Directory
285 if(mpriv->p.current->d) {
286 if(mpriv->dir_action) {
287 int fname_len = strlen(mpriv->dir) + strlen(mpriv->p.current->p.txt) + 1;
288 char filename[fname_len];
289 char* str;
290 sprintf(filename,"%s%s",mpriv->dir,mpriv->p.current->p.txt);
291 str = replace_path(mpriv->dir_action,filename);
292 c = mp_input_parse_cmd(str);
293 if(str != mpriv->dir_action)
294 free(str);
295 } else { // Default action : open this dirctory ourself
296 int l = strlen(mpriv->dir);
297 char *slash = NULL, *p = NULL;
298 if(strcmp(mpriv->p.current->p.txt,"../") == 0) {
299 if(l <= 1) break;
300 mpriv->dir[l-1] = '\0';
301 slash = strrchr(mpriv->dir,'/');
302 #if defined(__MINGW32__) || defined(__CYGWIN__)
303 if (!slash)
304 slash = strrchr(mpriv->dir,'\\');
305 #endif
306 if(!slash) break;
307 slash[1] = '\0';
308 p = strdup(mpriv->dir);
309 } else {
310 p = malloc(l + strlen(mpriv->p.current->p.txt) + 1);
311 sprintf(p,"%s%s",mpriv->dir,mpriv->p.current->p.txt);
313 menu_list_uninit(menu,free_entry);
314 if(!open_dir(menu,p)) {
315 mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_CantOpenDirectory,p);
316 menu->cl = 1;
318 free(p);
320 } else { // Files
321 int fname_len = strlen(mpriv->dir) + strlen(mpriv->p.current->p.txt) + 1;
322 char filename[fname_len];
323 char *str;
324 sprintf(filename,"%s%s",mpriv->dir,mpriv->p.current->p.txt);
325 str = replace_path(mpriv->file_action,filename);
326 c = mp_input_parse_cmd(str);
327 if(str != mpriv->file_action)
328 free(str);
330 if(c) {
331 mp_input_queue_cmd(c);
332 if(mpriv->auto_close)
333 menu->cl = 1;
335 } break;
336 case MENU_CMD_ACTION: {
337 int fname_len = strlen(mpriv->dir) + strlen(mpriv->p.current->p.txt) + 1;
338 char filename[fname_len];
339 char *str;
340 sprintf(filename,"%s%s",mpriv->dir,mpriv->p.current->p.txt);
341 str = replace_path(action, filename);
342 mp_input_queue_cmd(mp_input_parse_cmd(str));
343 if(str != action)
344 free(str);
345 } break;
346 default:
347 menu_list_read_cmd(menu,cmd);
351 static void read_key(menu_t* menu,int c){
352 if(c == KEY_BS)
353 read_cmd(menu,MENU_CMD_LEFT);
354 else {
355 char **str;
356 for (str=mpriv->actions; str && *str; str++)
357 if (c == (*str)[0]) {
358 action = &(*str)[2];
359 read_cmd(menu,MENU_CMD_ACTION);
360 break;
362 if (!str || !*str)
363 menu_list_read_key(menu,c,1);
367 static void clos(menu_t* menu) {
368 menu_list_uninit(menu,free_entry);
369 free(mpriv->dir);
372 static int open_fs(menu_t* menu, char* args) {
373 char *path = mpriv->path;
374 int r = 0;
375 char wd[PATH_MAX+1];
376 args = NULL; // Warning kill
378 menu->draw = menu_list_draw;
379 menu->read_cmd = read_cmd;
380 menu->read_key = read_key;
381 menu->close = clos;
383 getcwd(wd,PATH_MAX);
384 if(!path || path[0] == '\0') {
385 int l = strlen(wd) + 2;
386 char b[l];
387 sprintf(b,"%s/",wd);
388 r = open_dir(menu,b);
389 } else if(path[0] != '/') {
390 int al = strlen(path);
391 int l = strlen(wd) + al + 3;
392 char b[l];
393 if(b[al-1] != '/')
394 sprintf(b,"%s/%s/",wd,path);
395 else
396 sprintf(b,"%s/%s",wd,path);
397 r = open_dir(menu,b);
398 } else
399 r = open_dir(menu,path);
401 return r;
404 const menu_info_t menu_info_filesel = {
405 "File seletor menu",
406 "filesel",
407 "Albeu",
410 "fs_cfg",
411 sizeof(struct menu_priv_s),
412 &cfg_dflt,
413 cfg_fields
415 open_fs