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>
41
#include "libmpcodecs/img_format.h"
42
#include "libmpcodecs/mp_image.h"
45
#include "menu_list.h"
46
#include "input/input.h"
47
#include "osdep/keycodes.h"
49
#define MENU_KEEP_PATH "/tmp/mp_current_path"
52
char *menu_chroot = NULL;
61
char* dir; // current dir
71
static struct menu_priv_s cfg_dflt = {
83
#define ST_OFF(m) M_ST_OFF(struct menu_priv_s,m)
85
static const m_option_t cfg_fields[] = {
86
MENU_LIST_PRIV_FIELDS,
87
{ "path", ST_OFF(path), CONF_TYPE_STRING, 0, 0, 0, NULL },
88
{ "title", ST_OFF(title), CONF_TYPE_STRING, 0, 0, 0, NULL },
89
{ "file-action", ST_OFF(file_action), CONF_TYPE_STRING, 0, 0, 0, NULL },
90
{ "dir-action", ST_OFF(dir_action), CONF_TYPE_STRING, 0, 0, 0, NULL },
91
{ "actions", ST_OFF(actions), CONF_TYPE_STRING_LIST, 0, 0, 0, NULL},
92
{ "filter", ST_OFF(filter), CONF_TYPE_STRING, 0, 0, 0, NULL},
93
{ NULL, NULL, NULL, 0,0,0,NULL }
96
#define mpriv (menu->priv)
98
static void free_entry(list_entry_t* entry) {
103
static char* replace_path(char* title , char* dir , int escape) {
104
char *p = strstr(title,"%p");
106
int tl = strlen(title);
107
int dl = strlen(dir);
110
char *r, *n, *d = dir;
116
else if (*d == '\'') /* ' -> \'\\\'\' */
127
else if (*dir == '\'') { /* ' -> \'\\\'\' */
128
*n++ = '\\'; *n++ = '\'';
129
*n++ = '\\'; *n++ = '\\';
130
*n++ = '\\'; *n++ = '\'';
134
} while ((*n++ = *dir++));
142
typedef int (*kill_warn)(const void*, const void*);
144
static int mylstat(char *dir, char *file,struct stat* st) {
145
int l = strlen(dir) + strlen(file);
147
if (!strcmp("..", file)) {
152
if (s[l] == '/' || s[l] == '\\')
157
slash = strrchr(s, '/');
160
slash = strrchr(s,'\\');
167
sprintf(s,"%s/%s",dir,file);
171
static int compare(char **a, char **b){
172
if((*a)[strlen(*a) - 1] == '/') {
173
if((*b)[strlen(*b) - 1] == '/')
174
return strcmp(*b, *a) ;
178
if((*b)[strlen(*b) - 1] == '/')
181
return strcmp(*b, *a);
185
static char **get_extensions(menu_t *menu){
186
char **extensions, ext[32];
193
fp = fopen(mpriv->filter, "r");
197
extensions = malloc(sizeof(*extensions));
200
while(fgets(ext,sizeof(ext),fp)) {
202
int s = strlen (ext);
204
if(ext[s-1] == '\n') {
209
extensions = realloc(extensions, ++n * sizeof(*extensions));
210
extensions = realloc(extensions, ++n * sizeof(*extensions));
212
for (l=extensions; *l; l++);
221
static void free_extensions(char **extensions){
223
char **l = extensions;
230
static int open_dir(menu_t* menu,char* args) {
231
char **namelist, **tp;
238
char **extensions, **elem, *ext;
240
menu_list_init(menu);
243
mpriv->dir = strdup(args);
244
if(mpriv->p.title && mpriv->p.title != mpriv->title && mpriv->p.title != cfg_dflt.p.title)
245
free(mpriv->p.title);
247
mpriv->p.title = replace_path(mpriv->title,mpriv->dir,0);
249
if ((dirp = opendir (mpriv->dir)) == NULL){
250
mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_OpendirError, strerror(errno));
255
path_fp = open (MENU_KEEP_PATH, O_CREAT | O_WRONLY | O_TRUNC, 0666);
257
write (path_fp, mpriv->dir, strlen (mpriv->dir));
262
namelist = malloc(sizeof(char *));
263
extensions = get_extensions(menu);
266
while ((dp = readdir(dirp)) != NULL) {
267
if(dp->d_name[0] == '.' && strcmp(dp->d_name,"..") != 0)
269
if (menu_chroot && !strcmp (dp->d_name,"..")) {
270
size_t len = strlen (menu_chroot);
271
if ((strlen (mpriv->dir) == len || strlen (mpriv->dir) == len + 1)
272
&& !strncmp (mpriv->dir, menu_chroot, len))
275
if (mylstat(args,dp->d_name,&st))
277
if (file_filter && extensions && !S_ISDIR(st.st_mode)) {
278
if((ext = strrchr(dp->d_name,'.')) == NULL)
283
if (!strcasecmp(ext, *elem))
289
if(n%20 == 0){ // Get some more mem
290
if((tp = realloc(namelist, (n+20) * sizeof (char *)))
292
mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_ReallocError, strerror(errno));
299
namelist[n] = malloc(strlen(dp->d_name) + 2);
300
if(namelist[n] == NULL){
301
mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_MallocError, strerror(errno));
306
strcpy(namelist[n], dp->d_name);
307
if(S_ISDIR(st.st_mode))
308
strcat(namelist[n], "/");
313
free_extensions (extensions);
316
qsort(namelist, n, sizeof(char *), (kill_warn)compare);
319
mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_ReaddirError,strerror(errno));
323
if((e = calloc(1,sizeof(list_entry_t))) != NULL){
325
e->p.txt = strdup(namelist[n]);
326
if(strchr(namelist[n], '/') != NULL)
328
menu_list_add_entry(menu,e);
330
mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_MallocError, strerror(errno));
341
static void read_cmd(menu_t* menu,int cmd) {
344
mpriv->p.current = mpriv->p.menu; // Hack : we consider that the first entry is ../
348
if(mpriv->p.current->d && !mpriv->dir_action) {
349
// Default action : open this dirctory ourself
350
int l = strlen(mpriv->dir);
351
char *slash = NULL, *p = NULL;
352
if(strcmp(mpriv->p.current->p.txt,"../") == 0) {
354
mpriv->dir[l-1] = '\0';
355
slash = strrchr(mpriv->dir,'/');
358
slash = strrchr(mpriv->dir,'\\');
362
p = strdup(mpriv->dir);
364
p = malloc(l + strlen(mpriv->p.current->p.txt) + 1);
365
sprintf(p,"%s%s",mpriv->dir,mpriv->p.current->p.txt);
367
menu_list_uninit(menu,free_entry);
368
if(!open_dir(menu,p)) {
369
mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_LIBMENU_CantOpenDirectory,p);
373
} else { // File and directory dealt with action string.
374
int fname_len = strlen(mpriv->dir) + strlen(mpriv->p.current->p.txt) + 1;
375
char filename[fname_len];
377
char *action = mpriv->p.current->d ? mpriv->dir_action:mpriv->file_action;
378
sprintf(filename,"%s%s",mpriv->dir,mpriv->p.current->p.txt);
379
str = replace_path(action, filename,1);
380
mp_input_parse_and_queue_cmds(str);
385
case MENU_CMD_ACTION: {
386
int fname_len = strlen(mpriv->dir) + strlen(mpriv->p.current->p.txt) + 1;
387
char filename[fname_len];
389
sprintf(filename,"%s%s",mpriv->dir,mpriv->p.current->p.txt);
390
str = replace_path(action, filename,1);
391
mp_input_parse_and_queue_cmds(str);
396
menu_list_read_cmd(menu,cmd);
400
static int read_key(menu_t* menu,int c){
402
for (str=mpriv->actions; str && *str; str++)
403
if (c == (*str)[0]) {
405
read_cmd(menu,MENU_CMD_ACTION);
408
if (menu_dflt_read_key(menu, c))
410
return menu_list_jump_to_key(menu, c);
413
static void clos(menu_t* menu) {
414
menu_list_uninit(menu,free_entry);
418
static int open_fs(menu_t* menu, char* args) {
419
char *path = mpriv->path;
421
char wd[PATH_MAX+1], b[PATH_MAX+1];
422
args = NULL; // Warning kill
424
menu->draw = menu_list_draw;
425
menu->read_cmd = read_cmd;
426
menu->read_key = read_key;
430
if (!path || path[0] == '\0') {
434
path_fp = open (MENU_KEEP_PATH, O_RDONLY);
436
if (!fstat (path_fp, &st) && (st.st_size > 0)) {
437
path = malloc(st.st_size+1);
438
path[st.st_size] = '\0';
439
if (!((read(path_fp, path, st.st_size) == st.st_size) && path[0] == '/'
440
&& !stat(path, &st) && S_ISDIR(st.st_mode))) {
451
if (!path || path[0] == '\0') {
454
if (filename && !strstr(filename, "://") && (path=realpath(filename, b))) {
455
slash = strrchr(path, '/');
457
// FIXME: Do we need and can convert all '\\' in path to '/' on win32?
459
slash = strrchr(path, '\\');
468
if (path[0] != '/') {
469
if(path[strlen(path)-1] != '/')
470
snprintf(b,sizeof(b),"%s/%s/",wd,path);
472
snprintf(b,sizeof(b),"%s/%s",wd,path);
474
} else if (path[strlen(path)-1]!='/') {
475
sprintf(b,"%s/",path);
478
if (menu_chroot && menu_chroot[0] == '/') {
479
int l = strlen(menu_chroot);
480
if (l > 0 && menu_chroot[l-1] == '/')
482
if (strncmp(menu_chroot, path, l) || (path[l] != '\0' && path[l] != '/')) {
483
if (menu_chroot[l] == '/')
486
sprintf(b,"%s/",menu_chroot);
491
r = open_dir(menu,path);
496
const menu_info_t menu_info_filesel = {
503
sizeof(struct menu_priv_s),