Proper gettext initialization.
[cboard.git] / src / filebrowser.c
blob6644e2c4a7aa509d81cb6bb9cd9bbf98a55c5edc
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
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
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <err.h>
27 #include <errno.h>
28 #include <panel.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <string.h>
32 #include <time.h>
33 #include <pwd.h>
35 #ifdef HAVE_GLOB_H
36 #include <glob.h>
37 #endif
39 #ifdef HAVE_DIRENT_H
40 #include <dirent.h>
41 #endif
43 #include "misc.h"
44 #include "chess.h"
45 #include "window.h"
46 #include "message.h"
47 #include "menu.h"
48 #include "input.h"
49 #include "filebrowser.h"
50 #include "common.h"
51 #include "conf.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" \
61 " ESCAPE - abort"
64 static void free_file_browser()
66 int i;
68 if (!files)
69 return;
71 for (i = 0; files[i]; i++) {
72 free(files[i]->name);
73 free(files[i]->path);
74 free(files[i]->st);
75 free(files[i]);
78 free(files);
79 files = NULL;
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;
86 char *path = in->arg;
87 struct menu_item_s **items = m->items;
88 char *p;
89 char pattern[255];
90 int i, n = 0;
91 struct stat st;
92 int which = 2;
93 int len;
94 int x = GLOB_ERR;
95 #ifdef HAVE_GLOB_NOMATCH
96 int ret;
97 #endif
98 glob_t g;
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);
106 if (items) {
107 for (i = 0; items[i]; i++)
108 free(items[i]);
111 free(items);
112 items = m->items = NULL;
113 free_file_browser();
114 m->nofree = 1;
116 new_glob:
117 #ifdef HAVE_GLOB_NOMATCH
118 if ((ret = glob(pattern, x, NULL, &g)) != 0 && ret != GLOB_NOMATCH) {
119 #else
120 if (glob(pattern, x, NULL, &g) != 0) {
121 #endif
122 cmessage(_("[ ERROR ]"), _("[ press any key to continue ]"), "glob() failed:\n%s", pattern);
123 return NULL;
126 for (i = 0; i < g.gl_pathc; i++) {
127 struct tm *tp;
128 char tbuf[16];
129 char sbuf[64];
131 if (stat(g.gl_pathv[i], &st) == -1)
132 continue;
134 if ((p = strrchr(g.gl_pathv[i], '/')) != NULL)
135 p++;
136 else
137 p = g.gl_pathv[i];
139 if (which) {
140 if (!S_ISDIR(st.st_mode))
141 continue;
143 if (p[0] == '.' && p[1] == 0)
144 continue;
146 else {
147 if (S_ISDIR(st.st_mode))
148 continue;
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]);
154 len = strlen(p) + 2;
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) == '/') {
164 p -= 2;
165 *p = 0;
167 if (strlen(files[n]->path)) {
168 while (*p != '/')
169 p--;
171 *p = 0;
174 if (!strlen(files[n]->path)) {
175 p = files[n]->path;
176 *p++ = '/';
177 *p = 0;
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);
186 n++;
189 which--;
190 files[n] = NULL;
192 if (which > 0) {
193 snprintf(pattern, sizeof(pattern), "%s/*", path);
194 globfree(&g);
195 goto new_glob;
197 else if (which == 0) {
198 snprintf(pattern, sizeof(pattern), "%s/%s", path, config.pattern);
199 globfree(&g);
200 goto new_glob;
203 globfree(&g);
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;
213 free(win->title);
214 win->title = strdup(path);
215 items[i] = NULL;
216 m->items = items;
217 return items;
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"
231 " ESCAPE - abort"
235 static void file_browser_select(struct menu_input_s *m)
237 struct input_s *in = m->data;
238 char *path = in->arg;
239 struct stat st;
241 if (stat(files[m->selected]->path, &st) == -1) {
242 message(_("[ ERROR ]"), _("[ press any key to continue ]"), "%s", strerror(errno));
243 return;
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));
249 return;
252 free(path);
253 path = strdup(files[m->selected]->path);
254 in->arg = path;
255 m->selected = 0;
257 if (oldwd)
258 free(oldwd);
260 oldwd = strdup(path);
261 return;
264 strncpy(in->buf, files[m->selected]->path, sizeof(in->buf));
265 set_field_buffer(in->fields[0], 0, in->buf);
266 pushkey = -1;
269 static void file_browser_finalize(WIN *win)
271 struct input_s *in = win->data;
273 free(in->arg);
274 free_file_browser();
277 static void file_browser_home(struct menu_input_s *m)
279 struct input_s *in = m->data;
280 char *path = in->arg;
281 struct passwd *pw;
283 free(path);
284 pw = getpwuid(getuid());
285 path = strdup(pw->pw_dir);
286 in->arg = path;
287 m->selected = 0;
289 if (oldwd)
290 free(oldwd);
292 oldwd = strdup(path);
295 static void do_file_browser_expression_finalize(WIN *win)
297 struct input_data_s *in = win->data;
299 if (!in->str)
300 return;
302 if (config.pattern)
303 free(config.pattern);
305 config.pattern = strdup(in->str);
306 free(in->str);
307 free(in);
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)
322 pushkey = -1;
325 static void file_browser_print(WIN *win)
327 int i, len = 0;
328 struct menu_input_s *m = win->data;
330 for (i = 0; m->items[i]; i++) {
331 int n = strlen(m->items[i]->value);
333 if (len < n)
334 len = n;
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;
345 char *p;
346 char path[FILENAME_MAX];
348 if (!oldwd && config.savedirectory) {
349 if ((p = pathfix(config.savedirectory)) == NULL)
350 return;
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));
359 else if (!oldwd)
360 getcwd(path, sizeof(path));
361 else
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);
372 return;