Update copyright year.
[cboard.git] / src / filebrowser.c
blobdbae16a7982f41888d88db7def66bca4daac0014
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 "strings.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, ANYKEY, "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(BROWSER_HELP, ANYKEY, "%s", filebrowser_help);
225 static void file_browser_select(struct menu_input_s *m)
227 struct input_s *in = m->data;
228 char *path = in->arg;
229 struct stat st;
231 if (stat(files[m->selected]->path, &st) == -1) {
232 message(ERROR, ANYKEY, "%s", strerror(errno));
233 return;
236 if (S_ISDIR(st.st_mode)) {
237 if (access(files[m->selected]->path, R_OK) != 0) {
238 cmessage(files[m->selected]->path, ANYKEY, "%s", strerror(errno));
239 return;
242 free(path);
243 path = strdup(files[m->selected]->path);
244 in->arg = path;
245 m->selected = 0;
247 if (oldwd)
248 free(oldwd);
250 oldwd = strdup(path);
251 return;
254 strncpy(in->buf, files[m->selected]->path, sizeof(in->buf));
255 set_field_buffer(in->fields[0], 0, in->buf);
256 pushkey = -1;
259 static void file_browser_finalize(WIN *win)
261 struct input_s *in = win->data;
263 free(in->arg);
264 free_file_browser();
267 static void file_browser_home(struct menu_input_s *m)
269 struct input_s *in = m->data;
270 char *path = in->arg;
271 struct passwd *pw;
273 free(path);
274 pw = getpwuid(getuid());
275 path = strdup(pw->pw_dir);
276 in->arg = path;
277 m->selected = 0;
279 if (oldwd)
280 free(oldwd);
282 oldwd = strdup(path);
285 static void do_file_browser_expression_finalize(WIN *win)
287 struct input_data_s *in = win->data;
289 if (!in->str)
290 return;
292 if (config.pattern)
293 free(config.pattern);
295 config.pattern = strdup(in->str);
296 free(in->str);
297 free(in);
298 pushkey = REFRESH_MENU;
301 static void file_browser_expression(struct menu_input_s *m)
303 struct input_data_s *in;
305 in = Calloc(1, sizeof(struct input_data_s));
306 in->efunc = do_file_browser_expression_finalize;
307 construct_input(BROWSER_EXPR, config.pattern, 1, 1, NULL, NULL, NULL, 0, in, -1, -1);
310 static void file_browser_abort(struct menu_input_s *m)
312 pushkey = -1;
315 static void file_browser_print(WIN *win)
317 int i, len = 0;
318 struct menu_input_s *m = win->data;
320 for (i = 0; m->items[i]; i++) {
321 int n = strlen(m->items[i]->value);
323 if (len < n)
324 len = n;
327 mvwprintw(win->w, m->print_line, 1, "%*s %-*s", len, m->item->value,
328 win->cols - len - 3, m->item->name);
331 void file_browser(void *arg)
333 struct menu_key_s **keys = NULL;
334 struct input_s *in = arg;
335 char *p;
336 char path[FILENAME_MAX];
338 if (!oldwd && config.savedirectory) {
339 if ((p = pathfix(config.savedirectory)) == NULL)
340 return;
342 strncpy(path, p, sizeof(path));
344 if (access(path, R_OK) == -1) {
345 cmessage(ERROR, ANYKEY, "%s: %s", path, strerror(errno));
346 getcwd(path, sizeof(path));
349 else if (!oldwd)
350 getcwd(path, sizeof(path));
351 else
352 strncpy(path, oldwd, sizeof(path));
354 in->arg = strdup(path);
355 add_menu_key(&keys, '\n', file_browser_select);
356 add_menu_key(&keys, KEY_F(1), file_browser_help);
357 add_menu_key(&keys, '~', file_browser_home);
358 add_menu_key(&keys, CTRL('e'), file_browser_expression);
359 add_menu_key(&keys, KEY_ESCAPE, file_browser_abort);
360 construct_menu(LINES - 4, 0, -1, -1, NULL, 0, get_file_items, keys, in,
361 file_browser_print, file_browser_finalize);
362 return;