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
29 #include <sys/types.h>
49 #include "filebrowser.h"
53 const char *filebrowser_help
= {
54 " UP/DOWN - previous/next menu item\n" \
55 " HOME/END - first/last menu item\n" \
56 " PGDN/PGUP - next/previous page\n" \
57 " a-zA-Z0-9 - jump to item\n" \
58 " ENTER - select item\n" \
59 " ~ - change to home directory\n" \
60 " CTRL-e - change filename expression\n" \
64 static void free_file_browser()
71 for (i
= 0; files
[i
]; i
++) {
82 static struct menu_item_s
**get_file_items(WIN
*win
)
84 struct menu_input_s
*m
= win
->data
;
85 struct input_s
*in
= m
->data
;
87 struct menu_item_s
**items
= m
->items
;
95 #ifdef HAVE_GLOB_NOMATCH
101 * First find hidden directories in the working directory. Then non-hidden
102 * directories, then apply the config.pattern to regular files.
104 snprintf(pattern
, sizeof(pattern
), "%s/.?*", path
);
107 for (i
= 0; items
[i
]; i
++)
112 items
= m
->items
= NULL
;
117 #ifdef HAVE_GLOB_NOMATCH
118 if ((ret
= glob(pattern
, x
, NULL
, &g
)) != 0 && ret
!= GLOB_NOMATCH
) {
120 if (glob(pattern
, x
, NULL
, &g
) != 0) {
122 cmessage(_("[ ERROR ]"), _("[ press any key to continue ]"), "glob() failed:\n%s", pattern
);
126 for (i
= 0; i
< g
.gl_pathc
; i
++) {
131 if (stat(g
.gl_pathv
[i
], &st
) == -1)
134 if ((p
= strrchr(g
.gl_pathv
[i
], '/')) != NULL
)
140 if (!S_ISDIR(st
.st_mode
))
143 if (p
[0] == '.' && p
[1] == 0)
147 if (S_ISDIR(st
.st_mode
))
151 files
= Realloc(files
, (n
+ 2) * sizeof(struct file_s
*));
152 files
[n
] = Malloc(sizeof(struct file_s
));
153 files
[n
]->path
= strdup(g
.gl_pathv
[i
]);
155 files
[n
]->name
= Malloc(len
);
156 strcpy(files
[n
]->name
, p
);
158 if (S_ISDIR(st
.st_mode
)) {
159 files
[n
]->name
[len
- 2] = '/';
160 files
[n
]->name
[len
- 1] = 0;
161 p
= files
[n
]->path
+ strlen(files
[n
]->path
) - 1;
163 if (*p
== '.' && *(p
- 1) == '.' && *(p
- 2) == '/') {
167 if (strlen(files
[n
]->path
)) {
174 if (!strlen(files
[n
]->path
)) {
182 tp
= localtime(&st
.st_mtime
);
183 strftime(tbuf
, sizeof(tbuf
), "%b %d %T", tp
);
184 snprintf(sbuf
, sizeof(sbuf
), "%s %6i", tbuf
, (int)st
.st_size
);
185 files
[n
]->st
= strdup(sbuf
);
193 snprintf(pattern
, sizeof(pattern
), "%s/*", path
);
197 else if (which
== 0) {
198 snprintf(pattern
, sizeof(pattern
), "%s/%s", path
, config
.pattern
);
205 for (i
= 0; files
[i
]; i
++) {
206 items
= Realloc(items
, (i
+2) * sizeof(struct menu_item_s
*));
207 items
[i
] = Malloc(sizeof(struct menu_item_s
));
208 items
[i
]->name
= files
[i
]->name
;
209 items
[i
]->value
= files
[i
]->st
;
210 items
[i
]->selected
= 0;
214 win
->title
= strdup(path
);
220 static void file_browser_help(struct menu_input_s
*m
)
222 message(_("File Browser Keys"), _("[ press any key to continue ]"), "%s",
224 " UP/DOWN - previous/next menu item\n"
225 " HOME/END - first/last menu item\n"
226 " PGDN/PGUP - next/previous page\n"
227 " a-zA-Z0-9 - jump to item\n"
228 " ENTER - select item\n"
229 " ~ - change to home directory\n"
230 " CTRL-e - change filename expression\n"
235 static void file_browser_select(struct menu_input_s
*m
)
237 struct input_s
*in
= m
->data
;
238 char *path
= in
->arg
;
241 if (stat(files
[m
->selected
]->path
, &st
) == -1) {
242 message(_("[ ERROR ]"), _("[ press any key to continue ]"), "%s", strerror(errno
));
246 if (S_ISDIR(st
.st_mode
)) {
247 if (access(files
[m
->selected
]->path
, R_OK
) != 0) {
248 cmessage(files
[m
->selected
]->path
, _("[ press any key to continue ]"), "%s", strerror(errno
));
253 path
= strdup(files
[m
->selected
]->path
);
260 oldwd
= strdup(path
);
264 strncpy(in
->buf
, files
[m
->selected
]->path
, sizeof(in
->buf
));
265 set_field_buffer(in
->fields
[0], 0, in
->buf
);
269 static void file_browser_finalize(WIN
*win
)
271 struct input_s
*in
= win
->data
;
277 static void file_browser_home(struct menu_input_s
*m
)
279 struct input_s
*in
= m
->data
;
280 char *path
= in
->arg
;
284 pw
= getpwuid(getuid());
285 path
= strdup(pw
->pw_dir
);
292 oldwd
= strdup(path
);
295 static void do_file_browser_expression_finalize(WIN
*win
)
297 struct input_data_s
*in
= win
->data
;
303 free(config
.pattern
);
305 config
.pattern
= strdup(in
->str
);
308 pushkey
= REFRESH_MENU
;
311 static void file_browser_expression(struct menu_input_s
*m
)
313 struct input_data_s
*in
;
315 in
= Calloc(1, sizeof(struct input_data_s
));
316 in
->efunc
= do_file_browser_expression_finalize
;
317 construct_input(_("Filename Expression"), config
.pattern
, 1, 1, NULL
, NULL
, NULL
, 0, in
, -1, -1);
320 static void file_browser_abort(struct menu_input_s
*m
)
325 static void file_browser_print(WIN
*win
)
328 struct menu_input_s
*m
= win
->data
;
330 for (i
= 0; m
->items
[i
]; i
++) {
331 int n
= strlen(m
->items
[i
]->value
);
337 mvwprintw(win
->w
, m
->print_line
, 1, "%*s %-*s", len
, m
->item
->value
,
338 win
->cols
- len
- 3, m
->item
->name
);
341 void file_browser(void *arg
)
343 struct menu_key_s
**keys
= NULL
;
344 struct input_s
*in
= arg
;
346 char path
[FILENAME_MAX
];
348 if (!oldwd
&& config
.savedirectory
) {
349 if ((p
= pathfix(config
.savedirectory
)) == NULL
)
352 strncpy(path
, p
, sizeof(path
));
354 if (access(path
, R_OK
) == -1) {
355 cmessage(_("[ ERROR ]"), _("[ press any key to continue ]"), "%s: %s", path
, strerror(errno
));
356 getcwd(path
, sizeof(path
));
360 getcwd(path
, sizeof(path
));
362 strncpy(path
, oldwd
, sizeof(path
));
364 in
->arg
= strdup(path
);
365 add_menu_key(&keys
, '\n', file_browser_select
);
366 add_menu_key(&keys
, KEY_F(1), file_browser_help
);
367 add_menu_key(&keys
, '~', file_browser_home
);
368 add_menu_key(&keys
, CTRL('e'), file_browser_expression
);
369 add_menu_key(&keys
, KEY_ESCAPE
, file_browser_abort
);
370 construct_menu(LINES
- 4, 0, -1, -1, NULL
, 0, get_file_items
, keys
, in
,
371 file_browser_print
, file_browser_finalize
);