Update URL's to GitLab.
[cboard.git] / src / filebrowser.c
blob9c82c7a47c69eec477a41afa1bb8588f65152731
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2007-2018 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 <sys/types.h>
29 #include <sys/stat.h>
30 #include <string.h>
31 #include <time.h>
32 #include <pwd.h>
34 #ifdef HAVE_GLOB_H
35 #include <glob.h>
36 #endif
38 #ifdef HAVE_DIRENT_H
39 #include <dirent.h>
40 #endif
42 #include "misc.h"
43 #include "common.h"
44 #include "window.h"
45 #include "message.h"
46 #include "menu.h"
47 #include "input.h"
48 #include "filebrowser.h"
49 #include "common.h"
50 #include "conf.h"
52 static void
53 free_file_browser ()
55 int i;
57 if (!files)
58 return;
60 for (i = 0; files[i]; i++)
62 free (files[i]->name);
63 free (files[i]->path);
64 free (files[i]->st);
65 free (files[i]);
68 free (files);
69 files = NULL;
72 static struct menu_item_s **
73 get_file_items (WIN * win)
75 struct menu_input_s *m = win->data;
76 struct input_s *in = m->data;
77 char *path = in->arg;
78 struct menu_item_s **items = m->items;
79 char *p;
80 char pattern[255];
81 int i, n = 0;
82 struct stat st;
83 int which = 2;
84 int len;
85 int x = GLOB_ERR;
86 #ifdef HAVE_GLOB_NOMATCH
87 int ret;
88 #endif
89 glob_t g;
92 * First find hidden directories in the working directory. Then non-hidden
93 * directories, then apply the config.pattern to regular files.
95 snprintf (pattern, sizeof (pattern), "%s/.?*", path);
97 if (items)
99 for (i = 0; items[i]; i++)
100 free (items[i]);
103 free (items);
104 items = m->items = NULL;
105 free_file_browser ();
106 m->nofree = 1;
108 new_glob:
109 #ifdef HAVE_GLOB_NOMATCH
110 if ((ret = glob (pattern, x, NULL, &g)) != 0 && ret != GLOB_NOMATCH)
112 #else
113 if (glob (pattern, x, NULL, &g) != 0)
115 #endif
116 cmessage (ERROR_STR, ANY_KEY_STR, "glob() failed:\n%s", pattern);
117 return NULL;
120 for (i = 0; i < g.gl_pathc; i++)
122 struct tm *tp;
123 char tbuf[16];
124 char sbuf[64];
126 if (stat (g.gl_pathv[i], &st) == -1)
127 continue;
129 if ((p = strrchr (g.gl_pathv[i], '/')) != NULL)
130 p++;
131 else
132 p = g.gl_pathv[i];
134 if (which)
136 if (!S_ISDIR (st.st_mode))
137 continue;
139 if (p[0] == '.' && p[1] == 0)
140 continue;
142 else
144 if (S_ISDIR (st.st_mode))
145 continue;
148 files = Realloc (files, (n + 2) * sizeof (struct file_s *));
149 files[n] = Malloc (sizeof (struct file_s));
150 files[n]->path = strdup (g.gl_pathv[i]);
151 len = strlen (p) + 2;
152 files[n]->name = Malloc (len);
153 strcpy (files[n]->name, p);
155 if (S_ISDIR (st.st_mode))
157 files[n]->name[len - 2] = '/';
158 files[n]->name[len - 1] = 0;
159 p = files[n]->path + strlen (files[n]->path) - 1;
161 if (*p == '.' && *(p - 1) == '.' && *(p - 2) == '/')
163 p -= 2;
164 *p = 0;
166 if (strlen (files[n]->path))
168 while (*p != '/')
169 p--;
171 *p = 0;
174 if (!strlen (files[n]->path))
176 p = files[n]->path;
177 *p++ = '/';
178 *p = 0;
183 tp = localtime (&st.st_mtime);
184 strftime (tbuf, sizeof (tbuf), "%b %d %T", tp);
185 snprintf (sbuf, sizeof (sbuf), "%s %6i", tbuf, (int) st.st_size);
186 files[n]->st = strdup (sbuf);
187 n++;
190 which--;
191 files[n] = NULL;
193 if (which > 0)
195 snprintf (pattern, sizeof (pattern), "%s/*", path);
196 globfree (&g);
197 goto new_glob;
199 else if (which == 0)
201 snprintf (pattern, sizeof (pattern), "%s/%s", path, config.pattern);
202 globfree (&g);
203 goto new_glob;
206 globfree (&g);
208 for (i = 0; files[i]; i++)
210 items = Realloc (items, (i + 2) * sizeof (struct menu_item_s *));
211 items[i] = Malloc (sizeof (struct menu_item_s));
212 items[i]->name = files[i]->name;
213 items[i]->value = files[i]->st;
214 items[i]->selected = 0;
217 free (win->title);
218 win->title = strdup (path);
219 items[i] = NULL;
220 m->items = items;
221 return items;
224 static void
225 file_browser_help (struct menu_input_s *m)
227 message (_("File Browser Keys"), ANY_KEY_STR, "%s",
228 _(" UP/DOWN - previous/next menu item\n"
229 " HOME/END - first/last menu item\n"
230 " PGDN/PGUP - next/previous page\n"
231 " a-zA-Z0-9 - jump to item\n"
232 " ENTER - select item\n"
233 " ~ - change to home directory\n"
234 " CTRL-e - change filename expression\n"
235 " ESCAPE - abort"));
238 static void
239 file_browser_select (struct menu_input_s *m)
241 struct input_s *in = m->data;
242 char *path = in->arg;
243 struct stat st;
245 if (stat (files[m->selected]->path, &st) == -1)
247 message (ERROR_STR, ANY_KEY_STR, "%s", strerror (errno));
248 return;
251 if (S_ISDIR (st.st_mode))
253 if (access (files[m->selected]->path, R_OK) != 0)
255 cmessage (files[m->selected]->path, ANY_KEY_STR, "%s",
256 strerror (errno));
257 return;
260 free (path);
261 path = strdup (files[m->selected]->path);
262 in->arg = path;
263 m->selected = 0;
265 if (oldwd)
266 free (oldwd);
268 oldwd = strdup (path);
269 return;
272 strncpy (in->buf, files[m->selected]->path, sizeof (in->buf) - 1);
273 in->buf[sizeof (in->buf) - 1] = 0;
274 set_field_buffer (in->fields[0], 0, in->buf);
275 pushkey = -1;
278 static void
279 file_browser_finalize (WIN * win)
281 struct input_s *in = win->data;
283 free (in->arg);
284 free_file_browser ();
287 static void
288 file_browser_home (struct menu_input_s *m)
290 struct input_s *in = m->data;
291 char *path = in->arg;
292 struct passwd *pw;
294 free (path);
295 pw = getpwuid (getuid ());
296 path = strdup (pw->pw_dir);
297 in->arg = path;
298 m->selected = 0;
300 if (oldwd)
301 free (oldwd);
303 oldwd = strdup (path);
306 static void
307 do_file_browser_expression_finalize (WIN * win)
309 struct input_data_s *in = win->data;
311 if (!in->str)
312 return;
314 if (config.pattern)
315 free (config.pattern);
317 config.pattern = strdup (in->str);
318 free (in->str);
319 free (in);
320 pushkey = REFRESH_MENU;
323 static void
324 file_browser_expression (struct menu_input_s *m)
326 struct input_data_s *in;
328 in = Calloc (1, sizeof (struct input_data_s));
329 in->efunc = do_file_browser_expression_finalize;
330 construct_input (_("Filename Expression"), config.pattern, 1, 1, NULL, NULL,
331 NULL, 0, in, -1, NULL, -1);
334 static void
335 file_browser_abort (struct menu_input_s *m)
337 pushkey = -1;
340 static void
341 file_browser_print (WIN * win)
343 int i, len = 0;
344 struct menu_input_s *m = win->data;
346 for (i = 0; m->items[i]; i++)
348 int n = strlen (m->items[i]->value);
350 if (len < n)
351 len = n;
354 mvwprintw (win->w, m->print_line, 1, "%*s %-*s", len, m->item->value,
355 win->cols - len - 3, m->item->name);
358 void
359 file_browser (void *arg)
361 struct menu_key_s **keys = NULL;
362 struct input_s *in = arg;
363 char *p;
364 char path[FILENAME_MAX] = { 0 };
366 if (!oldwd && config.savedirectory)
368 if ((p = pathfix (config.savedirectory)) == NULL)
369 return;
371 strncpy (path, p, sizeof (path) - 1);
373 if (access (path, R_OK) == -1)
375 cmessage (ERROR_STR, ANY_KEY_STR, "%s: %s", path, strerror (errno));
376 getcwd (path, sizeof (path));
379 else if (!oldwd)
380 getcwd (path, sizeof (path) - 1);
381 else
382 strncpy (path, oldwd, sizeof (path) - 1);
384 in->arg = strdup (path);
385 add_menu_key (&keys, '\n', file_browser_select);
386 add_menu_key (&keys, KEY_F (1), file_browser_help);
387 add_menu_key (&keys, '~', file_browser_home);
388 add_menu_key (&keys, CTRL_KEY ('e'), file_browser_expression);
389 add_menu_key (&keys, KEY_ESCAPE, file_browser_abort);
390 construct_menu (LINES - 4, 0, -1, -1, NULL, 0, get_file_items, keys, in,
391 file_browser_print, file_browser_finalize, NULL);
392 return;