1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2007-2011 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <sys/types.h>
48 #include "filebrowser.h"
52 static void free_file_browser()
59 for (i
= 0; files
[i
]; i
++) {
70 static struct menu_item_s
**get_file_items(WIN
*win
)
72 struct menu_input_s
*m
= win
->data
;
73 struct input_s
*in
= m
->data
;
75 struct menu_item_s
**items
= m
->items
;
83 #ifdef HAVE_GLOB_NOMATCH
89 * First find hidden directories in the working directory. Then non-hidden
90 * directories, then apply the config.pattern to regular files.
92 snprintf(pattern
, sizeof(pattern
), "%s/.?*", path
);
95 for (i
= 0; items
[i
]; i
++)
100 items
= m
->items
= NULL
;
105 #ifdef HAVE_GLOB_NOMATCH
106 if ((ret
= glob(pattern
, x
, NULL
, &g
)) != 0 && ret
!= GLOB_NOMATCH
) {
108 if (glob(pattern
, x
, NULL
, &g
) != 0) {
110 cmessage(ERROR_STR
, ANY_KEY_STR
, "glob() failed:\n%s", pattern
);
114 for (i
= 0; i
< g
.gl_pathc
; i
++) {
119 if (stat(g
.gl_pathv
[i
], &st
) == -1)
122 if ((p
= strrchr(g
.gl_pathv
[i
], '/')) != NULL
)
128 if (!S_ISDIR(st
.st_mode
))
131 if (p
[0] == '.' && p
[1] == 0)
135 if (S_ISDIR(st
.st_mode
))
139 files
= Realloc(files
, (n
+ 2) * sizeof(struct file_s
*));
140 files
[n
] = Malloc(sizeof(struct file_s
));
141 files
[n
]->path
= strdup(g
.gl_pathv
[i
]);
143 files
[n
]->name
= Malloc(len
);
144 strcpy(files
[n
]->name
, p
);
146 if (S_ISDIR(st
.st_mode
)) {
147 files
[n
]->name
[len
- 2] = '/';
148 files
[n
]->name
[len
- 1] = 0;
149 p
= files
[n
]->path
+ strlen(files
[n
]->path
) - 1;
151 if (*p
== '.' && *(p
- 1) == '.' && *(p
- 2) == '/') {
155 if (strlen(files
[n
]->path
)) {
162 if (!strlen(files
[n
]->path
)) {
170 tp
= localtime(&st
.st_mtime
);
171 strftime(tbuf
, sizeof(tbuf
), "%b %d %T", tp
);
172 snprintf(sbuf
, sizeof(sbuf
), "%s %6i", tbuf
, (int)st
.st_size
);
173 files
[n
]->st
= strdup(sbuf
);
181 snprintf(pattern
, sizeof(pattern
), "%s/*", path
);
185 else if (which
== 0) {
186 snprintf(pattern
, sizeof(pattern
), "%s/%s", path
, config
.pattern
);
193 for (i
= 0; files
[i
]; i
++) {
194 items
= Realloc(items
, (i
+2) * sizeof(struct menu_item_s
*));
195 items
[i
] = Malloc(sizeof(struct menu_item_s
));
196 items
[i
]->name
= files
[i
]->name
;
197 items
[i
]->value
= files
[i
]->st
;
198 items
[i
]->selected
= 0;
202 win
->title
= strdup(path
);
208 static void file_browser_help(struct menu_input_s
*m
)
210 message(_("File Browser Keys"), ANY_KEY_STR
, "%s",
212 " UP/DOWN - previous/next menu item\n"
213 " HOME/END - first/last menu item\n"
214 " PGDN/PGUP - next/previous page\n"
215 " a-zA-Z0-9 - jump to item\n"
216 " ENTER - select item\n"
217 " ~ - change to home directory\n"
218 " CTRL-e - change filename expression\n"
223 static void file_browser_select(struct menu_input_s
*m
)
225 struct input_s
*in
= m
->data
;
226 char *path
= in
->arg
;
229 if (stat(files
[m
->selected
]->path
, &st
) == -1) {
230 message(ERROR_STR
, ANY_KEY_STR
, "%s", strerror(errno
));
234 if (S_ISDIR(st
.st_mode
)) {
235 if (access(files
[m
->selected
]->path
, R_OK
) != 0) {
236 cmessage(files
[m
->selected
]->path
, ANY_KEY_STR
, "%s", strerror(errno
));
241 path
= strdup(files
[m
->selected
]->path
);
248 oldwd
= strdup(path
);
252 strncpy(in
->buf
, files
[m
->selected
]->path
, sizeof(in
->buf
)-1);
253 in
->buf
[sizeof(in
->buf
)-1] = 0;
254 set_field_buffer(in
->fields
[0], 0, in
->buf
);
258 static void file_browser_finalize(WIN
*win
)
260 struct input_s
*in
= win
->data
;
266 static void file_browser_home(struct menu_input_s
*m
)
268 struct input_s
*in
= m
->data
;
269 char *path
= in
->arg
;
273 pw
= getpwuid(getuid());
274 path
= strdup(pw
->pw_dir
);
281 oldwd
= strdup(path
);
284 static void do_file_browser_expression_finalize(WIN
*win
)
286 struct input_data_s
*in
= win
->data
;
292 free(config
.pattern
);
294 config
.pattern
= strdup(in
->str
);
297 pushkey
= REFRESH_MENU
;
300 static void file_browser_expression(struct menu_input_s
*m
)
302 struct input_data_s
*in
;
304 in
= Calloc(1, sizeof(struct input_data_s
));
305 in
->efunc
= do_file_browser_expression_finalize
;
306 construct_input(_("Filename Expression"), config
.pattern
, 1, 1, NULL
, NULL
, NULL
, 0, in
, -1, -1);
309 static void file_browser_abort(struct menu_input_s
*m
)
314 static void file_browser_print(WIN
*win
)
317 struct menu_input_s
*m
= win
->data
;
319 for (i
= 0; m
->items
[i
]; i
++) {
320 int n
= strlen(m
->items
[i
]->value
);
326 mvwprintw(win
->w
, m
->print_line
, 1, "%*s %-*s", len
, m
->item
->value
,
327 win
->cols
- len
- 3, m
->item
->name
);
330 void file_browser(void *arg
)
332 struct menu_key_s
**keys
= NULL
;
333 struct input_s
*in
= arg
;
335 char path
[FILENAME_MAX
] = {0};
337 if (!oldwd
&& config
.savedirectory
) {
338 if ((p
= pathfix(config
.savedirectory
)) == NULL
)
341 strncpy(path
, p
, sizeof(path
)-1);
343 if (access(path
, R_OK
) == -1) {
344 cmessage(ERROR_STR
, ANY_KEY_STR
, "%s: %s", path
, strerror(errno
));
345 getcwd(path
, sizeof(path
));
349 getcwd(path
, sizeof(path
)-1);
351 strncpy(path
, oldwd
, sizeof(path
)-1);
353 in
->arg
= strdup(path
);
354 add_menu_key(&keys
, '\n', file_browser_select
);
355 add_menu_key(&keys
, KEY_F(1), file_browser_help
);
356 add_menu_key(&keys
, '~', file_browser_home
);
357 add_menu_key(&keys
, CTRL_KEY('e'), file_browser_expression
);
358 add_menu_key(&keys
, KEY_ESCAPE
, file_browser_abort
);
359 construct_menu(LINES
- 4, 0, -1, -1, NULL
, 0, get_file_items
, keys
, in
,
360 file_browser_print
, file_browser_finalize
);