2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <sys/types.h>
39 #include "libmpcodecs/img_format.h"
40 #include "libmpcodecs/mp_image.h"
43 #include "menu_list.h"
44 #include "input/input.h"
45 #include "osdep/keycodes.h"
47 #define MENU_KEEP_PATH "/tmp/mp_current_path"
50 char *menu_chroot
= NULL
;
51 extern char *filename
;
60 char* dir
; // current dir
70 static struct menu_priv_s cfg_dflt
= {
82 #define ST_OFF(m) M_ST_OFF(struct menu_priv_s,m)
84 static m_option_t cfg_fields
[] = {
85 MENU_LIST_PRIV_FIELDS
,
86 { "path", ST_OFF(path
), CONF_TYPE_STRING
, 0, 0, 0, NULL
},
87 { "title", ST_OFF(title
), CONF_TYPE_STRING
, 0, 0, 0, NULL
},
88 { "file-action", ST_OFF(file_action
), CONF_TYPE_STRING
, 0, 0, 0, NULL
},
89 { "dir-action", ST_OFF(dir_action
), CONF_TYPE_STRING
, 0, 0, 0, NULL
},
90 { "actions", ST_OFF(actions
), CONF_TYPE_STRING_LIST
, 0, 0, 0, NULL
},
91 { "filter", ST_OFF(filter
), CONF_TYPE_STRING
, 0, 0, 0, NULL
},
92 { NULL
, NULL
, NULL
, 0,0,0,NULL
}
95 #define mpriv (menu->priv)
97 static void free_entry(list_entry_t
* entry
) {
102 static char* replace_path(char* title
, char* dir
, int escape
) {
103 char *p
= strstr(title
,"%p");
105 int tl
= strlen(title
);
106 int dl
= strlen(dir
);
109 char *r
, *n
, *d
= dir
;
115 else if (*d
== '\'') /* ' -> \'\\\'\' */
126 else if (*dir
== '\'') { /* ' -> \'\\\'\' */
127 *n
++ = '\\'; *n
++ = '\'';
128 *n
++ = '\\'; *n
++ = '\\';
129 *n
++ = '\\'; *n
++ = '\'';
133 } while ((*n
++ = *dir
++));
141 typedef int (*kill_warn
)(const void*, const void*);
143 static int mylstat(char *dir
, char *file
,struct stat
* st
) {
144 int l
= strlen(dir
) + strlen(file
);
146 if (!strcmp("..", file
)) {
150 #if defined(__MINGW32__) || defined(__CYGWIN__)
151 if (s
[l
] == '/' || s
[l
] == '\\')
156 slash
= strrchr(s
, '/');
157 #if defined(__MINGW32__) || defined(__CYGWIN__)
159 slash
= strrchr(s
,'\\');
166 sprintf(s
,"%s/%s",dir
,file
);
170 static int compare(char **a
, char **b
){
171 if((*a
)[strlen(*a
) - 1] == '/') {
172 if((*b
)[strlen(*b
) - 1] == '/')
173 return strcmp(*b
, *a
) ;
177 if((*b
)[strlen(*b
) - 1] == '/')
180 return strcmp(*b
, *a
);
184 static char **get_extensions(menu_t
*menu
){
185 char **extensions
, ext
[32];
192 fp
= fopen(mpriv
->filter
, "r");
196 extensions
= (char **) malloc(sizeof(*extensions
));
199 while(fgets(ext
,sizeof(ext
),fp
)) {
201 int s
= strlen (ext
);
203 if(ext
[s
-1] == '\n') {
207 e
= (char *) malloc(s
+1);
208 extensions
= (char **) realloc(extensions
, ++n
* sizeof(*extensions
));
209 extensions
= (char **) realloc(extensions
, ++n
* sizeof(*extensions
));
211 for (l
=extensions
; *l
; l
++);
220 static void free_extensions(char **extensions
){
222 char **l
= extensions
;
229 static int open_dir(menu_t
* menu
,char* args
) {
230 char **namelist
, **tp
;
238 extern int file_filter
;
239 char **extensions
, **elem
, *ext
;
241 menu_list_init(menu
);
245 mpriv
->dir
= strdup(args
);
246 if(mpriv
->p
.title
&& mpriv
->p
.title
!= mpriv
->title
&& mpriv
->p
.title
!= cfg_dflt
.p
.title
)
247 free(mpriv
->p
.title
);
248 p
= strstr(mpriv
->title
,"%p");
250 mpriv
->p
.title
= replace_path(mpriv
->title
,mpriv
->dir
,0);
252 if ((dirp
= opendir (mpriv
->dir
)) == NULL
){
253 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_OpendirError
, strerror(errno
));
258 path_fp
= open (MENU_KEEP_PATH
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0666);
260 write (path_fp
, mpriv
->dir
, strlen (mpriv
->dir
));
265 namelist
= (char **) malloc(sizeof(char *));
266 extensions
= get_extensions(menu
);
269 while ((dp
= readdir(dirp
)) != NULL
) {
270 if(dp
->d_name
[0] == '.' && strcmp(dp
->d_name
,"..") != 0)
272 if (menu_chroot
&& !strcmp (dp
->d_name
,"..")) {
273 size_t len
= strlen (menu_chroot
);
274 if ((strlen (mpriv
->dir
) == len
|| strlen (mpriv
->dir
) == len
+ 1)
275 && !strncmp (mpriv
->dir
, menu_chroot
, len
))
278 if (mylstat(args
,dp
->d_name
,&st
))
280 if (file_filter
&& extensions
&& !S_ISDIR(st
.st_mode
)) {
281 if((ext
= strrchr(dp
->d_name
,'.')) == NULL
)
286 if (!strcasecmp(ext
, *elem
))
292 if(n
%20 == 0){ // Get some more mem
293 if((tp
= (char **) realloc(namelist
, (n
+20) * sizeof (char *)))
295 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_ReallocError
, strerror(errno
));
302 namelist
[n
] = (char *) malloc(strlen(dp
->d_name
) + 2);
303 if(namelist
[n
] == NULL
){
304 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_MallocError
, strerror(errno
));
309 strcpy(namelist
[n
], dp
->d_name
);
310 if(S_ISDIR(st
.st_mode
))
311 strcat(namelist
[n
], "/");
316 free_extensions (extensions
);
319 qsort(namelist
, n
, sizeof(char *), (kill_warn
)compare
);
322 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_ReaddirError
,strerror(errno
));
326 if((e
= calloc(1,sizeof(list_entry_t
))) != NULL
){
328 e
->p
.txt
= strdup(namelist
[n
]);
329 if(strchr(namelist
[n
], '/') != NULL
)
331 menu_list_add_entry(menu
,e
);
333 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_MallocError
, strerror(errno
));
344 static void read_cmd(menu_t
* menu
,int cmd
) {
347 mpriv
->p
.current
= mpriv
->p
.menu
; // Hack : we consider that the first entry is ../
351 if(mpriv
->p
.current
->d
&& !mpriv
->dir_action
) {
352 // Default action : open this dirctory ourself
353 int l
= strlen(mpriv
->dir
);
354 char *slash
= NULL
, *p
= NULL
;
355 if(strcmp(mpriv
->p
.current
->p
.txt
,"../") == 0) {
357 mpriv
->dir
[l
-1] = '\0';
358 slash
= strrchr(mpriv
->dir
,'/');
359 #if defined(__MINGW32__) || defined(__CYGWIN__)
361 slash
= strrchr(mpriv
->dir
,'\\');
365 p
= strdup(mpriv
->dir
);
367 p
= malloc(l
+ strlen(mpriv
->p
.current
->p
.txt
) + 1);
368 sprintf(p
,"%s%s",mpriv
->dir
,mpriv
->p
.current
->p
.txt
);
370 menu_list_uninit(menu
,free_entry
);
371 if(!open_dir(menu
,p
)) {
372 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_CantOpenDirectory
,p
);
376 } else { // File and directory dealt with action string.
377 int fname_len
= strlen(mpriv
->dir
) + strlen(mpriv
->p
.current
->p
.txt
) + 1;
378 char filename
[fname_len
];
380 char *action
= mpriv
->p
.current
->d
? mpriv
->dir_action
:mpriv
->file_action
;
381 sprintf(filename
,"%s%s",mpriv
->dir
,mpriv
->p
.current
->p
.txt
);
382 str
= replace_path(action
, filename
,1);
383 mp_input_parse_and_queue_cmds(str
);
388 case MENU_CMD_ACTION
: {
389 int fname_len
= strlen(mpriv
->dir
) + strlen(mpriv
->p
.current
->p
.txt
) + 1;
390 char filename
[fname_len
];
392 sprintf(filename
,"%s%s",mpriv
->dir
,mpriv
->p
.current
->p
.txt
);
393 str
= replace_path(action
, filename
,1);
394 mp_input_parse_and_queue_cmds(str
);
399 menu_list_read_cmd(menu
,cmd
);
403 static int read_key(menu_t
* menu
,int c
){
405 for (str
=mpriv
->actions
; str
&& *str
; str
++)
406 if (c
== (*str
)[0]) {
408 read_cmd(menu
,MENU_CMD_ACTION
);
411 if (menu_dflt_read_key(menu
, c
))
413 return menu_list_jump_to_key(menu
, c
);
416 static void clos(menu_t
* menu
) {
417 menu_list_uninit(menu
,free_entry
);
421 static int open_fs(menu_t
* menu
, char* args
) {
422 char *path
= mpriv
->path
;
424 char wd
[PATH_MAX
+1], b
[PATH_MAX
+1];
425 args
= NULL
; // Warning kill
427 menu
->draw
= menu_list_draw
;
428 menu
->read_cmd
= read_cmd
;
429 menu
->read_key
= read_key
;
433 if (!path
|| path
[0] == '\0') {
437 path_fp
= open (MENU_KEEP_PATH
, O_RDONLY
);
439 if (!fstat (path_fp
, &st
) && (st
.st_size
> 0)) {
440 path
= malloc(st
.st_size
+1);
441 path
[st
.st_size
] = '\0';
442 if (!((read(path_fp
, path
, st
.st_size
) == st
.st_size
) && path
[0] == '/'
443 && !stat(path
, &st
) && S_ISDIR(st
.st_mode
))) {
454 if (!path
|| path
[0] == '\0') {
457 if (filename
&& !strstr(filename
, "://") && (path
=realpath(filename
, b
))) {
458 slash
= strrchr(path
, '/');
459 #if defined(__MINGW32__) || defined(__CYGWIN__)
460 // FIXME: Do we need and can convert all '\\' in path to '/' on win32?
462 slash
= strrchr(path
, '\\');
471 if (path
[0] != '/') {
472 if(path
[strlen(path
)-1] != '/')
473 snprintf(b
,sizeof(b
),"%s/%s/",wd
,path
);
475 snprintf(b
,sizeof(b
),"%s/%s",wd
,path
);
477 } else if (path
[strlen(path
)-1]!='/') {
478 sprintf(b
,"%s/",path
);
481 if (menu_chroot
&& menu_chroot
[0] == '/') {
482 int l
= strlen(menu_chroot
);
483 if (l
> 0 && menu_chroot
[l
-1] == '/')
485 if (strncmp(menu_chroot
, path
, l
) || (path
[l
] != '\0' && path
[l
] != '/')) {
486 if (menu_chroot
[l
] == '/')
489 sprintf(b
,"%s/",menu_chroot
);
494 r
= open_dir(menu
,path
);
499 const menu_info_t menu_info_filesel
= {
506 sizeof(struct menu_priv_s
),