Blame


1 71ee1627 2014-11-07 marcelgmr #include <stdlib.h>
2 bae1431c 2014-11-07 marcelgmr #include <stdint.h>
3 6beff8a2 2014-11-08 marcelgmr #include <ctype.h>
4 6beff8a2 2014-11-08 marcelgmr #include <string.h>
5 5f52c474 2014-11-08 marcelgmr #include <sys/types.h> /* pid_t, ... */
6 c04b0d89 2015-03-30 marcelgmr #include <stdio.h>
7 c04b0d89 2015-03-30 marcelgmr #include <limits.h> /* PATH_MAX */
8 71ee1627 2014-11-07 marcelgmr #include <locale.h> /* setlocale(), LC_ALL */
9 b7ee4ee2 2014-11-14 marcelgmr #include <unistd.h> /* chdir(), getcwd(), read(), close(), ... */
10 71ee1627 2014-11-07 marcelgmr #include <dirent.h> /* DIR, struct dirent, opendir(), ... */
11 71ee1627 2014-11-07 marcelgmr #include <sys/stat.h>
12 b7ee4ee2 2014-11-14 marcelgmr #include <fcntl.h> /* open() */
13 71ee1627 2014-11-07 marcelgmr #include <sys/wait.h> /* waitpid() */
14 b529416b 2014-11-11 marcelgmr #include <signal.h> /* struct sigaction, sigaction() */
15 8a757b0f 2015-03-07 marcelgmr #include <errno.h>
16 71ee1627 2014-11-07 marcelgmr #include <curses.h>
17 71ee1627 2014-11-07 marcelgmr
18 71ee1627 2014-11-07 marcelgmr #include "config.h"
19 71ee1627 2014-11-07 marcelgmr
20 3cd6bb98 2014-11-11 marcelgmr /* String buffers. */
21 576e768d 2014-11-08 marcelgmr #define ROWSZ 256
22 3cd6bb98 2014-11-11 marcelgmr static char ROW[ROWSZ];
23 a17e36e3 2014-11-07 marcelgmr #define STATUSSZ 256
24 3cd6bb98 2014-11-11 marcelgmr static char STATUS[STATUSSZ];
25 1447784d 2014-11-14 marcelgmr #define INPUTSZ 256
26 1447784d 2014-11-14 marcelgmr static char INPUT[INPUTSZ];
27 3cd6bb98 2014-11-11 marcelgmr
28 3cd6bb98 2014-11-11 marcelgmr /* Argument buffers for execvp(). */
29 71ee1627 2014-11-07 marcelgmr #define MAXARGS 256
30 3cd6bb98 2014-11-11 marcelgmr static char *ARGS[MAXARGS];
31 71ee1627 2014-11-07 marcelgmr
32 60128fcd 2014-11-15 marcelgmr /* Listing view parameters. */
33 60128fcd 2014-11-15 marcelgmr #define HEIGHT (LINES-4)
34 60128fcd 2014-11-15 marcelgmr #define STATUSPOS (COLS-16)
35 f05efd9e 2014-11-07 marcelgmr
36 3cd6bb98 2014-11-11 marcelgmr /* Listing view flags. */
37 bae1431c 2014-11-07 marcelgmr #define SHOW_FILES 0x01u
38 bae1431c 2014-11-07 marcelgmr #define SHOW_DIRS 0x02u
39 bae1431c 2014-11-07 marcelgmr #define SHOW_HIDDEN 0x04u
40 bae1431c 2014-11-07 marcelgmr
41 50c63039 2014-11-14 marcelgmr /* Marks parameters. */
42 18016333 2014-11-14 marcelgmr #define BULK_INIT 5
43 18016333 2014-11-14 marcelgmr #define BULK_THRESH 256
44 18016333 2014-11-14 marcelgmr
45 3cd6bb98 2014-11-11 marcelgmr /* Information associated to each entry in listing. */
46 8f853fb5 2015-03-25 marcelgmr typedef struct Row {
47 576e768d 2014-11-08 marcelgmr char *name;
48 576e768d 2014-11-08 marcelgmr off_t size;
49 18016333 2014-11-14 marcelgmr int marked;
50 eef51ac5 2015-03-24 marcelgmr } Row;
51 576e768d 2014-11-08 marcelgmr
52 5c4a6b62 2014-11-14 marcelgmr /* Dynamic array of marked entries. */
53 8f853fb5 2015-03-25 marcelgmr typedef struct Marks {
54 c04b0d89 2015-03-30 marcelgmr char dirpath[PATH_MAX];
55 18016333 2014-11-14 marcelgmr int bulk;
56 18016333 2014-11-14 marcelgmr int nentries;
57 18016333 2014-11-14 marcelgmr char **entries;
58 eef51ac5 2015-03-24 marcelgmr } Marks;
59 18016333 2014-11-14 marcelgmr
60 a022230d 2015-04-26 marcelgmr /* Line editing state. */
61 a022230d 2015-04-26 marcelgmr typedef struct Edit {
62 6110e5a1 2015-04-26 marcelgmr char buffer[INPUTSZ-1];
63 a022230d 2015-04-26 marcelgmr int left, right;
64 a022230d 2015-04-26 marcelgmr } Edit;
65 a022230d 2015-04-26 marcelgmr
66 3cd6bb98 2014-11-11 marcelgmr /* Global state. Some basic info is allocated for ten tabs. */
67 eef51ac5 2015-03-24 marcelgmr static struct Rover {
68 ada8fba9 2014-11-09 marcelgmr int tab;
69 71ee1627 2014-11-07 marcelgmr int nfiles;
70 ada8fba9 2014-11-09 marcelgmr int scroll[10];
71 7c74df90 2014-11-15 marcelgmr int esel[10];
72 47e9f26d 2014-11-09 marcelgmr uint8_t flags[10];
73 eef51ac5 2015-03-24 marcelgmr Row *rows;
74 71ee1627 2014-11-07 marcelgmr WINDOW *window;
75 c04b0d89 2015-03-30 marcelgmr char cwd[10][PATH_MAX];
76 eef51ac5 2015-03-24 marcelgmr Marks marks;
77 a022230d 2015-04-26 marcelgmr Edit edit;
78 6998a035 2015-05-31 marcelgmr int edit_scroll;
79 f05efd9e 2014-11-07 marcelgmr } rover;
80 71ee1627 2014-11-07 marcelgmr
81 3cd6bb98 2014-11-11 marcelgmr /* Macros for accessing global state. */
82 7c74df90 2014-11-15 marcelgmr #define ENAME(I) rover.rows[I].name
83 7c74df90 2014-11-15 marcelgmr #define ESIZE(I) rover.rows[I].size
84 18016333 2014-11-14 marcelgmr #define MARKED(I) rover.rows[I].marked
85 3cd6bb98 2014-11-11 marcelgmr #define SCROLL rover.scroll[rover.tab]
86 7c74df90 2014-11-15 marcelgmr #define ESEL rover.esel[rover.tab]
87 3cd6bb98 2014-11-11 marcelgmr #define FLAGS rover.flags[rover.tab]
88 3cd6bb98 2014-11-11 marcelgmr #define CWD rover.cwd[rover.tab]
89 845f2b87 2014-11-14 marcelgmr
90 60128fcd 2014-11-15 marcelgmr /* Helpers. */
91 60128fcd 2014-11-15 marcelgmr #define MIN(A, B) ((A) < (B) ? (A) : (B))
92 60128fcd 2014-11-15 marcelgmr #define MAX(A, B) ((A) > (B) ? (A) : (B))
93 7c74df90 2014-11-15 marcelgmr #define ISDIR(E) (strchr((E), '/') != NULL)
94 a022230d 2015-04-26 marcelgmr
95 a022230d 2015-04-26 marcelgmr /* Line Editing Macros. */
96 6110e5a1 2015-04-26 marcelgmr #define EDIT_FULL(E) ((E).left == (E).right)
97 a022230d 2015-04-26 marcelgmr #define EDIT_CAN_LEFT(E) ((E).left)
98 6110e5a1 2015-04-26 marcelgmr #define EDIT_CAN_RIGHT(E) ((E).right < INPUTSZ-1)
99 a022230d 2015-04-26 marcelgmr #define EDIT_LEFT(E) (E).buffer[(E).right--] = (E).buffer[--(E).left]
100 a022230d 2015-04-26 marcelgmr #define EDIT_RIGHT(E) (E).buffer[(E).left++] = (E).buffer[++(E).right]
101 a022230d 2015-04-26 marcelgmr #define EDIT_INSERT(E, C) (E).buffer[(E).left++] = (C)
102 a022230d 2015-04-26 marcelgmr #define EDIT_BACKSPACE(E) (E).left--
103 a022230d 2015-04-26 marcelgmr #define EDIT_DELETE(E) (E).right++
104 6110e5a1 2015-04-26 marcelgmr #define EDIT_CLEAR(E) do { (E).left = 0; (E).right = INPUTSZ-1; } while(0)
105 7c74df90 2014-11-15 marcelgmr
106 a022230d 2015-04-26 marcelgmr typedef enum EditStat {CONTINUE, CONFIRM, CANCEL} EditStat;
107 8f853fb5 2015-03-25 marcelgmr typedef enum Color {DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, MAGENTA, WHITE} Color;
108 845f2b87 2014-11-14 marcelgmr typedef int (*PROCESS)(const char *path);
109 576e768d 2014-11-08 marcelgmr
110 d06e977d 2014-11-14 marcelgmr static void
111 eef51ac5 2015-03-24 marcelgmr init_marks(Marks *marks)
112 18016333 2014-11-14 marcelgmr {
113 18016333 2014-11-14 marcelgmr strcpy(marks->dirpath, "");
114 18016333 2014-11-14 marcelgmr marks->bulk = BULK_INIT;
115 18016333 2014-11-14 marcelgmr marks->nentries = 0;
116 f41c2ea1 2014-12-23 marcelgmr marks->entries = calloc(marks->bulk, sizeof *marks->entries);
117 18016333 2014-11-14 marcelgmr }
118 18016333 2014-11-14 marcelgmr
119 5c4a6b62 2014-11-14 marcelgmr /* Unmark all entries. */
120 d06e977d 2014-11-14 marcelgmr static void
121 eef51ac5 2015-03-24 marcelgmr mark_none(Marks *marks)
122 18016333 2014-11-14 marcelgmr {
123 18016333 2014-11-14 marcelgmr int i;
124 18016333 2014-11-14 marcelgmr
125 8ba07de5 2014-11-14 marcelgmr strcpy(marks->dirpath, "");
126 18016333 2014-11-14 marcelgmr for (i = 0; i < marks->bulk && marks->nentries; i++)
127 18016333 2014-11-14 marcelgmr if (marks->entries[i]) {
128 18016333 2014-11-14 marcelgmr free(marks->entries[i]);
129 9a852838 2014-11-14 marcelgmr marks->entries[i] = NULL;
130 18016333 2014-11-14 marcelgmr marks->nentries--;
131 18016333 2014-11-14 marcelgmr }
132 18016333 2014-11-14 marcelgmr if (marks->bulk > BULK_THRESH) {
133 18016333 2014-11-14 marcelgmr /* Reset bulk to free some memory. */
134 18016333 2014-11-14 marcelgmr free(marks->entries);
135 18016333 2014-11-14 marcelgmr marks->bulk = BULK_INIT;
136 f41c2ea1 2014-12-23 marcelgmr marks->entries = calloc(marks->bulk, sizeof *marks->entries);
137 18016333 2014-11-14 marcelgmr }
138 18016333 2014-11-14 marcelgmr }
139 18016333 2014-11-14 marcelgmr
140 d06e977d 2014-11-14 marcelgmr static void
141 eef51ac5 2015-03-24 marcelgmr add_mark(Marks *marks, char *dirpath, char *entry)
142 18016333 2014-11-14 marcelgmr {
143 18016333 2014-11-14 marcelgmr int i;
144 18016333 2014-11-14 marcelgmr
145 18016333 2014-11-14 marcelgmr if (!strcmp(marks->dirpath, dirpath)) {
146 18016333 2014-11-14 marcelgmr /* Append mark to directory. */
147 18016333 2014-11-14 marcelgmr if (marks->nentries == marks->bulk) {
148 18016333 2014-11-14 marcelgmr /* Expand bulk to accomodate new entry. */
149 edb0e68a 2015-06-01 marcelgmr int extra = marks->bulk / 2;
150 18016333 2014-11-14 marcelgmr marks->bulk += extra; /* bulk *= 1.5; */
151 f41c2ea1 2014-12-23 marcelgmr marks->entries = realloc(marks->entries,
152 f41c2ea1 2014-12-23 marcelgmr marks->bulk * sizeof *marks->entries);
153 f41c2ea1 2014-12-23 marcelgmr memset(&marks->entries[marks->nentries], 0,
154 f41c2ea1 2014-12-23 marcelgmr extra * sizeof *marks->entries);
155 18016333 2014-11-14 marcelgmr i = marks->nentries;
156 590d39af 2014-12-02 marcelgmr } else {
157 18016333 2014-11-14 marcelgmr /* Search for empty slot (there must be one). */
158 18016333 2014-11-14 marcelgmr for (i = 0; i < marks->bulk; i++)
159 18016333 2014-11-14 marcelgmr if (!marks->entries[i])
160 18016333 2014-11-14 marcelgmr break;
161 18016333 2014-11-14 marcelgmr }
162 590d39af 2014-12-02 marcelgmr } else {
163 18016333 2014-11-14 marcelgmr /* Directory changed. Discard old marks. */
164 18016333 2014-11-14 marcelgmr mark_none(marks);
165 18016333 2014-11-14 marcelgmr strcpy(marks->dirpath, dirpath);
166 18016333 2014-11-14 marcelgmr i = 0;
167 18016333 2014-11-14 marcelgmr }
168 f41c2ea1 2014-12-23 marcelgmr marks->entries[i] = malloc(strlen(entry) + 1);
169 18016333 2014-11-14 marcelgmr strcpy(marks->entries[i], entry);
170 18016333 2014-11-14 marcelgmr marks->nentries++;
171 18016333 2014-11-14 marcelgmr }
172 18016333 2014-11-14 marcelgmr
173 d06e977d 2014-11-14 marcelgmr static void
174 eef51ac5 2015-03-24 marcelgmr del_mark(Marks *marks, char *entry)
175 18016333 2014-11-14 marcelgmr {
176 18016333 2014-11-14 marcelgmr int i;
177 18016333 2014-11-14 marcelgmr
178 18016333 2014-11-14 marcelgmr if (marks->nentries > 1) {
179 18016333 2014-11-14 marcelgmr for (i = 0; i < marks->bulk; i++)
180 18016333 2014-11-14 marcelgmr if (marks->entries[i] && !strcmp(marks->entries[i], entry))
181 18016333 2014-11-14 marcelgmr break;
182 18016333 2014-11-14 marcelgmr free(marks->entries[i]);
183 18016333 2014-11-14 marcelgmr marks->entries[i] = NULL;
184 18016333 2014-11-14 marcelgmr marks->nentries--;
185 590d39af 2014-12-02 marcelgmr } else
186 590d39af 2014-12-02 marcelgmr mark_none(marks);
187 18016333 2014-11-14 marcelgmr }
188 18016333 2014-11-14 marcelgmr
189 d06e977d 2014-11-14 marcelgmr static void
190 eef51ac5 2015-03-24 marcelgmr free_marks(Marks *marks)
191 18016333 2014-11-14 marcelgmr {
192 18016333 2014-11-14 marcelgmr int i;
193 18016333 2014-11-14 marcelgmr
194 18016333 2014-11-14 marcelgmr for (i = 0; i < marks->bulk && marks->nentries; i++)
195 18016333 2014-11-14 marcelgmr if (marks->entries[i]) {
196 18016333 2014-11-14 marcelgmr free(marks->entries[i]);
197 18016333 2014-11-14 marcelgmr marks->nentries--;
198 18016333 2014-11-14 marcelgmr }
199 18016333 2014-11-14 marcelgmr free(marks->entries);
200 18016333 2014-11-14 marcelgmr }
201 b25c9834 2014-11-14 marcelgmr
202 7896cfae 2015-04-17 marcelgmr static void update_view();
203 18016333 2014-11-14 marcelgmr
204 7896cfae 2015-04-17 marcelgmr /* SIGSEGV handler: clean up curses before exiting. */
205 7896cfae 2015-04-17 marcelgmr static void
206 7896cfae 2015-04-17 marcelgmr handle_segv(int sig)
207 7896cfae 2015-04-17 marcelgmr {
208 7896cfae 2015-04-17 marcelgmr (void) sig;
209 7896cfae 2015-04-17 marcelgmr endwin();
210 7896cfae 2015-04-17 marcelgmr fprintf(stderr, "Received SIGSEGV (segmentation fault).\n");
211 7896cfae 2015-04-17 marcelgmr exit(1);
212 7896cfae 2015-04-17 marcelgmr }
213 e1c42cfe 2014-11-11 marcelgmr
214 7896cfae 2015-04-17 marcelgmr /* SIGWINCH handler: resize application according to new terminal settings. */
215 71ee1627 2014-11-07 marcelgmr static void
216 7896cfae 2015-04-17 marcelgmr handle_winch(int sig)
217 71ee1627 2014-11-07 marcelgmr {
218 7896cfae 2015-04-17 marcelgmr (void) sig;
219 7896cfae 2015-04-17 marcelgmr delwin(rover.window);
220 7896cfae 2015-04-17 marcelgmr endwin();
221 7896cfae 2015-04-17 marcelgmr refresh();
222 7896cfae 2015-04-17 marcelgmr clear();
223 7896cfae 2015-04-17 marcelgmr rover.window = subwin(stdscr, LINES - 2, COLS, 1, 0);
224 7896cfae 2015-04-17 marcelgmr update_view();
225 7896cfae 2015-04-17 marcelgmr }
226 7896cfae 2015-04-17 marcelgmr
227 7896cfae 2015-04-17 marcelgmr static void
228 7896cfae 2015-04-17 marcelgmr enable_handlers()
229 7896cfae 2015-04-17 marcelgmr {
230 e1c42cfe 2014-11-11 marcelgmr struct sigaction sa;
231 e1c42cfe 2014-11-11 marcelgmr
232 7896cfae 2015-04-17 marcelgmr memset(&sa, 0, sizeof (struct sigaction));
233 7896cfae 2015-04-17 marcelgmr sa.sa_handler = handle_segv;
234 7896cfae 2015-04-17 marcelgmr sigaction(SIGSEGV, &sa, NULL);
235 7896cfae 2015-04-17 marcelgmr sa.sa_handler = handle_winch;
236 7896cfae 2015-04-17 marcelgmr sigaction(SIGWINCH, &sa, NULL);
237 7896cfae 2015-04-17 marcelgmr }
238 7896cfae 2015-04-17 marcelgmr
239 7896cfae 2015-04-17 marcelgmr static void
240 7896cfae 2015-04-17 marcelgmr disable_handlers()
241 7896cfae 2015-04-17 marcelgmr {
242 7896cfae 2015-04-17 marcelgmr struct sigaction sa;
243 7896cfae 2015-04-17 marcelgmr
244 7896cfae 2015-04-17 marcelgmr memset(&sa, 0, sizeof (struct sigaction));
245 7896cfae 2015-04-17 marcelgmr sa.sa_handler = SIG_DFL;
246 7896cfae 2015-04-17 marcelgmr sigaction(SIGSEGV, &sa, NULL);
247 7896cfae 2015-04-17 marcelgmr sigaction(SIGWINCH, &sa, NULL);
248 7896cfae 2015-04-17 marcelgmr }
249 7896cfae 2015-04-17 marcelgmr
250 7896cfae 2015-04-17 marcelgmr /* Do a fork-exec to external program (e.g. $EDITOR). */
251 7896cfae 2015-04-17 marcelgmr static void
252 7896cfae 2015-04-17 marcelgmr spawn()
253 7896cfae 2015-04-17 marcelgmr {
254 7896cfae 2015-04-17 marcelgmr pid_t pid;
255 7896cfae 2015-04-17 marcelgmr int status;
256 7896cfae 2015-04-17 marcelgmr
257 cf66423f 2015-06-01 marcelgmr setenv("RVSEL", rover.nfiles ? ENAME(ESEL) : "", 1);
258 7896cfae 2015-04-17 marcelgmr pid = fork();
259 7896cfae 2015-04-17 marcelgmr if (pid > 0) {
260 7896cfae 2015-04-17 marcelgmr /* fork() succeeded. */
261 7896cfae 2015-04-17 marcelgmr disable_handlers();
262 7896cfae 2015-04-17 marcelgmr endwin();
263 7896cfae 2015-04-17 marcelgmr waitpid(pid, &status, 0);
264 7896cfae 2015-04-17 marcelgmr enable_handlers();
265 7896cfae 2015-04-17 marcelgmr kill(getpid(), SIGWINCH);
266 7896cfae 2015-04-17 marcelgmr } else if (pid == 0) {
267 7896cfae 2015-04-17 marcelgmr /* Child process. */
268 7896cfae 2015-04-17 marcelgmr execvp(ARGS[0], ARGS);
269 7896cfae 2015-04-17 marcelgmr }
270 7896cfae 2015-04-17 marcelgmr }
271 7896cfae 2015-04-17 marcelgmr
272 7896cfae 2015-04-17 marcelgmr /* Curses setup. */
273 7896cfae 2015-04-17 marcelgmr static void
274 7896cfae 2015-04-17 marcelgmr init_term()
275 7896cfae 2015-04-17 marcelgmr {
276 71ee1627 2014-11-07 marcelgmr setlocale(LC_ALL, "");
277 71ee1627 2014-11-07 marcelgmr initscr();
278 71ee1627 2014-11-07 marcelgmr cbreak(); /* Get one character at a time. */
279 71ee1627 2014-11-07 marcelgmr noecho();
280 71ee1627 2014-11-07 marcelgmr nonl(); /* No NL->CR/NL on output. */
281 71ee1627 2014-11-07 marcelgmr intrflush(stdscr, FALSE);
282 71ee1627 2014-11-07 marcelgmr keypad(stdscr, TRUE);
283 71ee1627 2014-11-07 marcelgmr curs_set(FALSE); /* Hide blinking cursor. */
284 71ee1627 2014-11-07 marcelgmr if (has_colors()) {
285 eb265708 2015-03-24 marcelgmr short bg;
286 71ee1627 2014-11-07 marcelgmr start_color();
287 eb265708 2015-03-24 marcelgmr #ifdef NCURSES_EXT_FUNCS
288 eb265708 2015-03-24 marcelgmr use_default_colors();
289 eb265708 2015-03-24 marcelgmr bg = -1;
290 eb265708 2015-03-24 marcelgmr #else
291 eb265708 2015-03-24 marcelgmr bg = COLOR_BLACK;
292 eb265708 2015-03-24 marcelgmr #endif
293 eb265708 2015-03-24 marcelgmr init_pair(RED, COLOR_RED, bg);
294 eb265708 2015-03-24 marcelgmr init_pair(GREEN, COLOR_GREEN, bg);
295 eb265708 2015-03-24 marcelgmr init_pair(YELLOW, COLOR_YELLOW, bg);
296 eb265708 2015-03-24 marcelgmr init_pair(BLUE, COLOR_BLUE, bg);
297 eb265708 2015-03-24 marcelgmr init_pair(CYAN, COLOR_CYAN, bg);
298 eb265708 2015-03-24 marcelgmr init_pair(MAGENTA, COLOR_MAGENTA, bg);
299 eb265708 2015-03-24 marcelgmr init_pair(WHITE, COLOR_WHITE, bg);
300 71ee1627 2014-11-07 marcelgmr }
301 7c74df90 2014-11-15 marcelgmr atexit((void (*)(void)) endwin);
302 7896cfae 2015-04-17 marcelgmr enable_handlers();
303 71ee1627 2014-11-07 marcelgmr }
304 71ee1627 2014-11-07 marcelgmr
305 3cd6bb98 2014-11-11 marcelgmr /* Update the listing view. */
306 71ee1627 2014-11-07 marcelgmr static void
307 743e70b8 2014-11-14 marcelgmr update_view()
308 71ee1627 2014-11-07 marcelgmr {
309 222db952 2014-11-08 marcelgmr int i, j;
310 38347b2a 2015-03-30 marcelgmr int numsize;
311 576e768d 2014-11-08 marcelgmr int ishidden, isdir;
312 18016333 2014-11-14 marcelgmr int marking;
313 71ee1627 2014-11-07 marcelgmr
314 41aae0b0 2014-11-11 marcelgmr mvhline(0, 0, ' ', COLS);
315 41aae0b0 2014-11-11 marcelgmr attr_on(A_BOLD, NULL);
316 41aae0b0 2014-11-11 marcelgmr color_set(RVC_TABNUM, NULL);
317 38347b2a 2015-03-30 marcelgmr mvaddch(0, COLS - 2, rover.tab + '0');
318 41aae0b0 2014-11-11 marcelgmr color_set(DEFAULT, NULL);
319 41aae0b0 2014-11-11 marcelgmr attr_off(A_BOLD, NULL);
320 38347b2a 2015-03-30 marcelgmr if (rover.marks.nentries) {
321 e5fe9820 2015-04-17 marcelgmr numsize = snprintf(STATUS, STATUSSZ, "%d", rover.marks.nentries);
322 38347b2a 2015-03-30 marcelgmr color_set(RVC_NMARKS, NULL);
323 38347b2a 2015-03-30 marcelgmr mvaddstr(0, COLS - 3 - numsize, STATUS);
324 38347b2a 2015-03-30 marcelgmr color_set(DEFAULT, NULL);
325 38347b2a 2015-03-30 marcelgmr } else
326 38347b2a 2015-03-30 marcelgmr numsize = -1;
327 38347b2a 2015-03-30 marcelgmr color_set(RVC_CWD, NULL);
328 38347b2a 2015-03-30 marcelgmr mvaddnstr(0, 0, CWD, COLS - 4 - numsize);
329 38347b2a 2015-03-30 marcelgmr color_set(DEFAULT, NULL);
330 41aae0b0 2014-11-11 marcelgmr wcolor_set(rover.window, RVC_BORDER, NULL);
331 41aae0b0 2014-11-11 marcelgmr wborder(rover.window, 0, 0, 0, 0, 0, 0, 0, 0);
332 41aae0b0 2014-11-11 marcelgmr wcolor_set(rover.window, DEFAULT, NULL);
333 667d4907 2014-11-14 marcelgmr /* Selection might not be visible, due to cursor wrapping or window
334 667d4907 2014-11-14 marcelgmr shrinking. In that case, the scroll must be moved to make it visible. */
335 60128fcd 2014-11-15 marcelgmr SCROLL = MAX(MIN(SCROLL, ESEL), ESEL - HEIGHT + 1);
336 18016333 2014-11-14 marcelgmr marking = !strcmp(CWD, rover.marks.dirpath);
337 ada8fba9 2014-11-09 marcelgmr for (i = 0, j = SCROLL; i < HEIGHT && j < rover.nfiles; i++, j++) {
338 7c74df90 2014-11-15 marcelgmr ishidden = ENAME(j)[0] == '.';
339 7c74df90 2014-11-15 marcelgmr isdir = ISDIR(ENAME(j));
340 7c74df90 2014-11-15 marcelgmr if (j == ESEL)
341 f05efd9e 2014-11-07 marcelgmr wattr_on(rover.window, A_REVERSE, NULL);
342 576e768d 2014-11-08 marcelgmr if (ishidden)
343 37233869 2014-11-07 marcelgmr wcolor_set(rover.window, RVC_HIDDEN, NULL);
344 576e768d 2014-11-08 marcelgmr else if (isdir)
345 37233869 2014-11-07 marcelgmr wcolor_set(rover.window, RVC_DIR, NULL);
346 37233869 2014-11-07 marcelgmr else
347 37233869 2014-11-07 marcelgmr wcolor_set(rover.window, RVC_FILE, NULL);
348 165b8d9e 2015-04-23 marcelgmr if (!isdir) {
349 ddca2129 2015-04-23 marcelgmr char *suffix, *suffixes = "BKMGTPEZY";
350 ddca2129 2015-04-23 marcelgmr off_t human_size = ESIZE(j) * 10;
351 ddca2129 2015-04-23 marcelgmr for (suffix = suffixes; human_size >= 10240; suffix++)
352 165b8d9e 2015-04-23 marcelgmr human_size = (human_size + 512) / 1024;
353 ddca2129 2015-04-23 marcelgmr if (*suffix == 'B')
354 ddca2129 2015-04-23 marcelgmr snprintf(ROW, ROWSZ, "%s%*d %c", ENAME(j),
355 ddca2129 2015-04-23 marcelgmr (int) (COLS - strlen(ENAME(j)) - 6),
356 ddca2129 2015-04-23 marcelgmr (int) human_size / 10, *suffix);
357 ddca2129 2015-04-23 marcelgmr else
358 ddca2129 2015-04-23 marcelgmr snprintf(ROW, ROWSZ, "%s%*d.%d %c", ENAME(j),
359 ddca2129 2015-04-23 marcelgmr (int) (COLS - strlen(ENAME(j)) - 8),
360 ddca2129 2015-04-23 marcelgmr (int) human_size / 10, (int) human_size % 10, *suffix);
361 165b8d9e 2015-04-23 marcelgmr } else
362 7c74df90 2014-11-15 marcelgmr strcpy(ROW, ENAME(j));
363 a81852bf 2014-11-08 marcelgmr mvwhline(rover.window, i + 1, 1, ' ', COLS - 2);
364 a651a76d 2014-11-14 marcelgmr if (marking && MARKED(j))
365 e6a7541a 2014-11-14 marcelgmr mvwaddch(rover.window, i + 1, 1, RVS_MARK);
366 18016333 2014-11-14 marcelgmr else
367 18016333 2014-11-14 marcelgmr mvwaddch(rover.window, i + 1, 1, ' ');
368 b9837001 2014-11-24 marcelgmr mvwaddnstr(rover.window, i + 1, 2, ROW, COLS - 4);
369 37233869 2014-11-07 marcelgmr wcolor_set(rover.window, DEFAULT, NULL);
370 7c74df90 2014-11-15 marcelgmr if (j == ESEL)
371 f05efd9e 2014-11-07 marcelgmr wattr_off(rover.window, A_REVERSE, NULL);
372 a81852bf 2014-11-08 marcelgmr }
373 37087140 2015-03-30 marcelgmr for (;i < HEIGHT; i++)
374 37087140 2015-03-30 marcelgmr mvwhline(rover.window, i + 1, 1, ' ', COLS - 2);
375 a81852bf 2014-11-08 marcelgmr if (rover.nfiles > HEIGHT) {
376 a81852bf 2014-11-08 marcelgmr int center, height;
377 edb0e68a 2015-06-01 marcelgmr center = (SCROLL + (HEIGHT / 2)) * HEIGHT / rover.nfiles;
378 a81852bf 2014-11-08 marcelgmr height = (HEIGHT-1) * HEIGHT / rover.nfiles;
379 a81852bf 2014-11-08 marcelgmr if (!height) height = 1;
380 a81852bf 2014-11-08 marcelgmr wcolor_set(rover.window, RVC_BORDER, NULL);
381 a81852bf 2014-11-08 marcelgmr wborder(rover.window, 0, 0, 0, 0, 0, 0, 0, 0);
382 2a2b72b6 2014-11-08 marcelgmr wcolor_set(rover.window, RVC_SCROLLBAR, NULL);
383 edb0e68a 2015-06-01 marcelgmr mvwvline(rover.window, center-(height/2)+1, COLS-1, RVS_SCROLLBAR, height);
384 a81852bf 2014-11-08 marcelgmr wcolor_set(rover.window, DEFAULT, NULL);
385 71ee1627 2014-11-07 marcelgmr }
386 47e9f26d 2014-11-09 marcelgmr STATUS[0] = FLAGS & SHOW_FILES ? 'F' : ' ';
387 47e9f26d 2014-11-09 marcelgmr STATUS[1] = FLAGS & SHOW_DIRS ? 'D' : ' ';
388 47e9f26d 2014-11-09 marcelgmr STATUS[2] = FLAGS & SHOW_HIDDEN ? 'H' : ' ';
389 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles)
390 222db952 2014-11-08 marcelgmr strcpy(ROW, "0/0");
391 bb90b2d2 2014-11-08 marcelgmr else
392 e5fe9820 2015-04-17 marcelgmr snprintf(ROW, ROWSZ, "%d/%d", ESEL + 1, rover.nfiles);
393 e5fe9820 2015-04-17 marcelgmr snprintf(STATUS+3, STATUSSZ-3, "%12s", ROW);
394 e1f31679 2014-11-07 marcelgmr color_set(RVC_STATUS, NULL);
395 50c63039 2014-11-14 marcelgmr mvaddstr(LINES - 1, STATUSPOS, STATUS);
396 e1f31679 2014-11-07 marcelgmr color_set(DEFAULT, NULL);
397 37087140 2015-03-30 marcelgmr wrefresh(rover.window);
398 71ee1627 2014-11-07 marcelgmr }
399 71ee1627 2014-11-07 marcelgmr
400 7896cfae 2015-04-17 marcelgmr /* Show a message on the status bar. */
401 7896cfae 2015-04-17 marcelgmr static void
402 7896cfae 2015-04-17 marcelgmr message(const char *msg, Color color)
403 41aae0b0 2014-11-11 marcelgmr {
404 7896cfae 2015-04-17 marcelgmr int len, pos;
405 7896cfae 2015-04-17 marcelgmr
406 7896cfae 2015-04-17 marcelgmr len = strlen(msg);
407 edb0e68a 2015-06-01 marcelgmr pos = (STATUSPOS - len) / 2;
408 7896cfae 2015-04-17 marcelgmr attr_on(A_BOLD, NULL);
409 7896cfae 2015-04-17 marcelgmr color_set(color, NULL);
410 7896cfae 2015-04-17 marcelgmr mvaddstr(LINES - 1, pos, msg);
411 7896cfae 2015-04-17 marcelgmr color_set(DEFAULT, NULL);
412 7896cfae 2015-04-17 marcelgmr attr_off(A_BOLD, NULL);
413 41aae0b0 2014-11-11 marcelgmr }
414 41aae0b0 2014-11-11 marcelgmr
415 7896cfae 2015-04-17 marcelgmr /* Clear message area, leaving only status info. */
416 41aae0b0 2014-11-11 marcelgmr static void
417 7896cfae 2015-04-17 marcelgmr clear_message()
418 41aae0b0 2014-11-11 marcelgmr {
419 7896cfae 2015-04-17 marcelgmr mvhline(LINES - 1, 0, ' ', STATUSPOS);
420 41aae0b0 2014-11-11 marcelgmr }
421 41aae0b0 2014-11-11 marcelgmr
422 3cd6bb98 2014-11-11 marcelgmr /* Comparison used to sort listing entries. */
423 3cd6bb98 2014-11-11 marcelgmr static int
424 3cd6bb98 2014-11-11 marcelgmr rowcmp(const void *a, const void *b)
425 3cd6bb98 2014-11-11 marcelgmr {
426 3cd6bb98 2014-11-11 marcelgmr int isdir1, isdir2, cmpdir;
427 eef51ac5 2015-03-24 marcelgmr const Row *r1 = a;
428 eef51ac5 2015-03-24 marcelgmr const Row *r2 = b;
429 7c74df90 2014-11-15 marcelgmr isdir1 = ISDIR(r1->name);
430 7c74df90 2014-11-15 marcelgmr isdir2 = ISDIR(r2->name);
431 3cd6bb98 2014-11-11 marcelgmr cmpdir = isdir2 - isdir1;
432 3cd6bb98 2014-11-11 marcelgmr return cmpdir ? cmpdir : strcoll(r1->name, r2->name);
433 3cd6bb98 2014-11-11 marcelgmr }
434 3cd6bb98 2014-11-11 marcelgmr
435 496dd2b0 2015-03-24 marcelgmr /* Get all entries in current working directory. */
436 3cd6bb98 2014-11-11 marcelgmr static int
437 496dd2b0 2015-03-24 marcelgmr ls(Row **rowsp, uint8_t flags)
438 3cd6bb98 2014-11-11 marcelgmr {
439 3cd6bb98 2014-11-11 marcelgmr DIR *dp;
440 3cd6bb98 2014-11-11 marcelgmr struct dirent *ep;
441 3cd6bb98 2014-11-11 marcelgmr struct stat statbuf;
442 eef51ac5 2015-03-24 marcelgmr Row *rows;
443 3cd6bb98 2014-11-11 marcelgmr int i, n;
444 3cd6bb98 2014-11-11 marcelgmr
445 496dd2b0 2015-03-24 marcelgmr if(!(dp = opendir("."))) return -1;
446 3cd6bb98 2014-11-11 marcelgmr n = -2; /* We don't want the entries "." and "..". */
447 3cd6bb98 2014-11-11 marcelgmr while (readdir(dp)) n++;
448 3cd6bb98 2014-11-11 marcelgmr rewinddir(dp);
449 f41c2ea1 2014-12-23 marcelgmr rows = malloc(n * sizeof *rows);
450 3cd6bb98 2014-11-11 marcelgmr i = 0;
451 3cd6bb98 2014-11-11 marcelgmr while ((ep = readdir(dp))) {
452 3cd6bb98 2014-11-11 marcelgmr if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
453 3cd6bb98 2014-11-11 marcelgmr continue;
454 3cd6bb98 2014-11-11 marcelgmr if (!(flags & SHOW_HIDDEN) && ep->d_name[0] == '.')
455 3cd6bb98 2014-11-11 marcelgmr continue;
456 f1e9b90e 2015-03-30 marcelgmr lstat(ep->d_name, &statbuf);
457 3cd6bb98 2014-11-11 marcelgmr if (S_ISDIR(statbuf.st_mode)) {
458 3cd6bb98 2014-11-11 marcelgmr if (flags & SHOW_DIRS) {
459 f41c2ea1 2014-12-23 marcelgmr rows[i].name = malloc(strlen(ep->d_name) + 2);
460 3cd6bb98 2014-11-11 marcelgmr strcpy(rows[i].name, ep->d_name);
461 3cd6bb98 2014-11-11 marcelgmr strcat(rows[i].name, "/");
462 3cd6bb98 2014-11-11 marcelgmr i++;
463 3cd6bb98 2014-11-11 marcelgmr }
464 590d39af 2014-12-02 marcelgmr } else if (flags & SHOW_FILES) {
465 f41c2ea1 2014-12-23 marcelgmr rows[i].name = malloc(strlen(ep->d_name) + 1);
466 3cd6bb98 2014-11-11 marcelgmr strcpy(rows[i].name, ep->d_name);
467 3cd6bb98 2014-11-11 marcelgmr rows[i].size = statbuf.st_size;
468 3cd6bb98 2014-11-11 marcelgmr i++;
469 3cd6bb98 2014-11-11 marcelgmr }
470 3cd6bb98 2014-11-11 marcelgmr }
471 3cd6bb98 2014-11-11 marcelgmr n = i; /* Ignore unused space in array caused by filters. */
472 f41c2ea1 2014-12-23 marcelgmr qsort(rows, n, sizeof (*rows), rowcmp);
473 3cd6bb98 2014-11-11 marcelgmr closedir(dp);
474 3cd6bb98 2014-11-11 marcelgmr *rowsp = rows;
475 3cd6bb98 2014-11-11 marcelgmr return n;
476 3cd6bb98 2014-11-11 marcelgmr }
477 3cd6bb98 2014-11-11 marcelgmr
478 3cd6bb98 2014-11-11 marcelgmr static void
479 eef51ac5 2015-03-24 marcelgmr free_rows(Row **rowsp, int nfiles)
480 3cd6bb98 2014-11-11 marcelgmr {
481 3cd6bb98 2014-11-11 marcelgmr int i;
482 3cd6bb98 2014-11-11 marcelgmr
483 3cd6bb98 2014-11-11 marcelgmr for (i = 0; i < nfiles; i++)
484 3cd6bb98 2014-11-11 marcelgmr free((*rowsp)[i].name);
485 3cd6bb98 2014-11-11 marcelgmr free(*rowsp);
486 3cd6bb98 2014-11-11 marcelgmr *rowsp = NULL;
487 3cd6bb98 2014-11-11 marcelgmr }
488 3cd6bb98 2014-11-11 marcelgmr
489 8f853fb5 2015-03-25 marcelgmr /* Change working directory to the path in CWD. */
490 71ee1627 2014-11-07 marcelgmr static void
491 ada8fba9 2014-11-09 marcelgmr cd(int reset)
492 71ee1627 2014-11-07 marcelgmr {
493 18016333 2014-11-14 marcelgmr int i, j;
494 18016333 2014-11-14 marcelgmr
495 d0cdbd3c 2014-11-15 marcelgmr message("Loading...", CYAN);
496 d0cdbd3c 2014-11-15 marcelgmr refresh();
497 60128fcd 2014-11-15 marcelgmr if (reset) ESEL = SCROLL = 0;
498 ea0214c3 2014-11-09 marcelgmr chdir(CWD);
499 f05efd9e 2014-11-07 marcelgmr if (rover.nfiles)
500 576e768d 2014-11-08 marcelgmr free_rows(&rover.rows, rover.nfiles);
501 496dd2b0 2015-03-24 marcelgmr rover.nfiles = ls(&rover.rows, FLAGS);
502 18016333 2014-11-14 marcelgmr if (!strcmp(CWD, rover.marks.dirpath)) {
503 18016333 2014-11-14 marcelgmr for (i = 0; i < rover.nfiles; i++) {
504 18016333 2014-11-14 marcelgmr for (j = 0; j < rover.marks.bulk; j++)
505 18016333 2014-11-14 marcelgmr if (
506 18016333 2014-11-14 marcelgmr rover.marks.entries[j] &&
507 7c74df90 2014-11-15 marcelgmr !strcmp(rover.marks.entries[j], ENAME(i))
508 18016333 2014-11-14 marcelgmr )
509 18016333 2014-11-14 marcelgmr break;
510 18016333 2014-11-14 marcelgmr MARKED(i) = j < rover.marks.bulk;
511 18016333 2014-11-14 marcelgmr }
512 590d39af 2014-12-02 marcelgmr } else
513 590d39af 2014-12-02 marcelgmr for (i = 0; i < rover.nfiles; i++)
514 590d39af 2014-12-02 marcelgmr MARKED(i) = 0;
515 d0cdbd3c 2014-11-15 marcelgmr clear_message();
516 743e70b8 2014-11-14 marcelgmr update_view();
517 548a3163 2014-11-14 marcelgmr }
518 548a3163 2014-11-14 marcelgmr
519 430cd7d8 2014-11-19 marcelgmr /* Select a target entry, if it is present. */
520 430cd7d8 2014-11-19 marcelgmr static void
521 430cd7d8 2014-11-19 marcelgmr try_to_sel(const char *target)
522 430cd7d8 2014-11-19 marcelgmr {
523 430cd7d8 2014-11-19 marcelgmr ESEL = 0;
524 f499f7c7 2014-12-03 marcelgmr if (!ISDIR(target))
525 f499f7c7 2014-12-03 marcelgmr while ((ESEL+1) < rover.nfiles && ISDIR(ENAME(ESEL)))
526 f499f7c7 2014-12-03 marcelgmr ESEL++;
527 00ecdc1e 2014-11-19 marcelgmr while ((ESEL+1) < rover.nfiles && strcoll(ENAME(ESEL), target) < 0)
528 430cd7d8 2014-11-19 marcelgmr ESEL++;
529 430cd7d8 2014-11-19 marcelgmr if (rover.nfiles > HEIGHT) {
530 edb0e68a 2015-06-01 marcelgmr SCROLL = ESEL - (HEIGHT / 2);
531 430cd7d8 2014-11-19 marcelgmr SCROLL = MIN(MAX(SCROLL, 0), rover.nfiles - HEIGHT);
532 430cd7d8 2014-11-19 marcelgmr }
533 430cd7d8 2014-11-19 marcelgmr }
534 430cd7d8 2014-11-19 marcelgmr
535 00ecdc1e 2014-11-19 marcelgmr /* Reload CWD, but try to keep selection. */
536 00ecdc1e 2014-11-19 marcelgmr static void
537 00ecdc1e 2014-11-19 marcelgmr reload()
538 00ecdc1e 2014-11-19 marcelgmr {
539 00ecdc1e 2014-11-19 marcelgmr if (rover.nfiles) {
540 00ecdc1e 2014-11-19 marcelgmr strcpy(INPUT, ENAME(ESEL));
541 00ecdc1e 2014-11-19 marcelgmr cd(1);
542 00ecdc1e 2014-11-19 marcelgmr try_to_sel(INPUT);
543 00ecdc1e 2014-11-19 marcelgmr update_view();
544 590d39af 2014-12-02 marcelgmr } else
545 590d39af 2014-12-02 marcelgmr cd(1);
546 00ecdc1e 2014-11-19 marcelgmr }
547 00ecdc1e 2014-11-19 marcelgmr
548 5c4a6b62 2014-11-14 marcelgmr /* Recursively process a source directory using CWD as destination root.
549 c8891c90 2014-12-23 marcelgmr For each node (i.e. directory), do the following:
550 c8891c90 2014-12-23 marcelgmr 1. call pre(destination);
551 c8891c90 2014-12-23 marcelgmr 2. call proc() on every child leaf (i.e. files);
552 c8891c90 2014-12-23 marcelgmr 3. recurse into every child node;
553 c8891c90 2014-12-23 marcelgmr 4. call pos(source).
554 c8891c90 2014-12-23 marcelgmr E.g. to move directory /src/ (and all its contents) inside /dst/:
555 c8891c90 2014-12-23 marcelgmr strcpy(CWD, "/dst/");
556 c8891c90 2014-12-23 marcelgmr process_dir(adddir, movfile, deldir, "/src/"); */
557 2a117cd2 2014-11-15 marcelgmr static int
558 845f2b87 2014-11-14 marcelgmr process_dir(PROCESS pre, PROCESS proc, PROCESS pos, const char *path)
559 548a3163 2014-11-14 marcelgmr {
560 2a117cd2 2014-11-15 marcelgmr int ret;
561 548a3163 2014-11-14 marcelgmr DIR *dp;
562 548a3163 2014-11-14 marcelgmr struct dirent *ep;
563 548a3163 2014-11-14 marcelgmr struct stat statbuf;
564 c04b0d89 2015-03-30 marcelgmr char subpath[PATH_MAX];
565 548a3163 2014-11-14 marcelgmr
566 2a117cd2 2014-11-15 marcelgmr ret = 0;
567 68ff0591 2014-11-14 marcelgmr if (pre) {
568 c04b0d89 2015-03-30 marcelgmr char dstpath[PATH_MAX];
569 68ff0591 2014-11-14 marcelgmr strcpy(dstpath, CWD);
570 68ff0591 2014-11-14 marcelgmr strcat(dstpath, path + strlen(rover.marks.dirpath));
571 2a117cd2 2014-11-15 marcelgmr ret |= pre(dstpath);
572 68ff0591 2014-11-14 marcelgmr }
573 2a117cd2 2014-11-15 marcelgmr if(!(dp = opendir(path))) return -1;
574 548a3163 2014-11-14 marcelgmr while ((ep = readdir(dp))) {
575 548a3163 2014-11-14 marcelgmr if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
576 548a3163 2014-11-14 marcelgmr continue;
577 e5fe9820 2015-04-17 marcelgmr snprintf(subpath, PATH_MAX, "%s%s", path, ep->d_name);
578 548a3163 2014-11-14 marcelgmr stat(subpath, &statbuf);
579 548a3163 2014-11-14 marcelgmr if (S_ISDIR(statbuf.st_mode)) {
580 548a3163 2014-11-14 marcelgmr strcat(subpath, "/");
581 2a117cd2 2014-11-15 marcelgmr ret |= process_dir(pre, proc, pos, subpath);
582 590d39af 2014-12-02 marcelgmr } else
583 590d39af 2014-12-02 marcelgmr ret |= proc(subpath);
584 548a3163 2014-11-14 marcelgmr }
585 548a3163 2014-11-14 marcelgmr closedir(dp);
586 2a117cd2 2014-11-15 marcelgmr if (pos) ret |= pos(path);
587 2a117cd2 2014-11-15 marcelgmr return ret;
588 548a3163 2014-11-14 marcelgmr }
589 548a3163 2014-11-14 marcelgmr
590 5c4a6b62 2014-11-14 marcelgmr /* Process all marked entries using CWD as destination root.
591 c8891c90 2014-12-23 marcelgmr All marked entries that are directories will be recursively processed.
592 c8891c90 2014-12-23 marcelgmr See process_dir() for details on the parameters. */
593 548a3163 2014-11-14 marcelgmr static void
594 845f2b87 2014-11-14 marcelgmr process_marked(PROCESS pre, PROCESS proc, PROCESS pos)
595 548a3163 2014-11-14 marcelgmr {
596 2a117cd2 2014-11-15 marcelgmr int i, ret;
597 c04b0d89 2015-03-30 marcelgmr char path[PATH_MAX];
598 548a3163 2014-11-14 marcelgmr
599 d0cdbd3c 2014-11-15 marcelgmr clear_message();
600 d0cdbd3c 2014-11-15 marcelgmr message("Processing...", CYAN);
601 d0cdbd3c 2014-11-15 marcelgmr refresh();
602 548a3163 2014-11-14 marcelgmr for (i = 0; i < rover.marks.bulk; i++)
603 548a3163 2014-11-14 marcelgmr if (rover.marks.entries[i]) {
604 2a117cd2 2014-11-15 marcelgmr ret = 0;
605 e5fe9820 2015-04-17 marcelgmr snprintf(path, PATH_MAX, "%s%s", rover.marks.dirpath, rover.marks.entries[i]);
606 7c74df90 2014-11-15 marcelgmr if (ISDIR(rover.marks.entries[i])) {
607 b25c9834 2014-11-14 marcelgmr if (!strncmp(path, CWD, strlen(path)))
608 2a117cd2 2014-11-15 marcelgmr ret = -1;
609 b25c9834 2014-11-14 marcelgmr else
610 2a117cd2 2014-11-15 marcelgmr ret = process_dir(pre, proc, pos, path);
611 590d39af 2014-12-02 marcelgmr } else
612 590d39af 2014-12-02 marcelgmr ret = proc(path);
613 2a117cd2 2014-11-15 marcelgmr if (!ret) del_mark(&rover.marks, rover.marks.entries[i]);
614 2a117cd2 2014-11-15 marcelgmr }
615 00ecdc1e 2014-11-19 marcelgmr reload();
616 2a117cd2 2014-11-15 marcelgmr if (!rover.marks.nentries)
617 bad36707 2014-11-19 marcelgmr message("Done.", GREEN);
618 2a117cd2 2014-11-15 marcelgmr else
619 bad36707 2014-11-19 marcelgmr message("Some errors occured.", RED);
620 3cd6bb98 2014-11-11 marcelgmr }
621 3cd6bb98 2014-11-11 marcelgmr
622 b7ee4ee2 2014-11-14 marcelgmr /* Wrappers for file operations. */
623 ca8ebdce 2014-11-14 marcelgmr static PROCESS delfile = unlink;
624 b7ee4ee2 2014-11-14 marcelgmr static PROCESS deldir = rmdir;
625 1447784d 2014-11-14 marcelgmr static int addfile(const char *path) {
626 1447784d 2014-11-14 marcelgmr /* Using creat(2) because mknod(2) doesn't seem to be portable. */
627 1447784d 2014-11-14 marcelgmr int ret;
628 1447784d 2014-11-14 marcelgmr
629 1447784d 2014-11-14 marcelgmr ret = creat(path, 0644);
630 1447784d 2014-11-14 marcelgmr if (ret < 0) return ret;
631 1447784d 2014-11-14 marcelgmr return close(ret);
632 1447784d 2014-11-14 marcelgmr }
633 ca8ebdce 2014-11-14 marcelgmr static int cpyfile(const char *srcpath) {
634 b7ee4ee2 2014-11-14 marcelgmr int src, dst, ret;
635 b7ee4ee2 2014-11-14 marcelgmr size_t size;
636 b7ee4ee2 2014-11-14 marcelgmr struct stat st;
637 b7ee4ee2 2014-11-14 marcelgmr char buf[BUFSIZ];
638 c04b0d89 2015-03-30 marcelgmr char dstpath[PATH_MAX];
639 b7ee4ee2 2014-11-14 marcelgmr
640 b7ee4ee2 2014-11-14 marcelgmr ret = src = open(srcpath, O_RDONLY);
641 b7ee4ee2 2014-11-14 marcelgmr if (ret < 0) return ret;
642 b7ee4ee2 2014-11-14 marcelgmr ret = fstat(src, &st);
643 b7ee4ee2 2014-11-14 marcelgmr if (ret < 0) return ret;
644 b7ee4ee2 2014-11-14 marcelgmr strcpy(dstpath, CWD);
645 b7ee4ee2 2014-11-14 marcelgmr strcat(dstpath, srcpath + strlen(rover.marks.dirpath));
646 b7ee4ee2 2014-11-14 marcelgmr ret = dst = creat(dstpath, st.st_mode);
647 b7ee4ee2 2014-11-14 marcelgmr if (ret < 0) return ret;
648 b7ee4ee2 2014-11-14 marcelgmr while ((size = read(src, buf, BUFSIZ)) > 0)
649 b7ee4ee2 2014-11-14 marcelgmr write(dst, buf, size);
650 b7ee4ee2 2014-11-14 marcelgmr close(src);
651 b7ee4ee2 2014-11-14 marcelgmr close(dst);
652 b7ee4ee2 2014-11-14 marcelgmr return 0;
653 b7ee4ee2 2014-11-14 marcelgmr }
654 b7ee4ee2 2014-11-14 marcelgmr static int adddir(const char *path) {
655 b7ee4ee2 2014-11-14 marcelgmr int ret;
656 b7ee4ee2 2014-11-14 marcelgmr struct stat st;
657 b7ee4ee2 2014-11-14 marcelgmr
658 b7ee4ee2 2014-11-14 marcelgmr ret = stat(CWD, &st);
659 b7ee4ee2 2014-11-14 marcelgmr if (ret < 0) return ret;
660 b7ee4ee2 2014-11-14 marcelgmr return mkdir(path, st.st_mode);
661 ca8ebdce 2014-11-14 marcelgmr }
662 0ea64589 2014-11-14 marcelgmr static int movfile(const char *srcpath) {
663 8a757b0f 2015-03-07 marcelgmr int ret;
664 c04b0d89 2015-03-30 marcelgmr char dstpath[PATH_MAX];
665 ca8ebdce 2014-11-14 marcelgmr
666 0ea64589 2014-11-14 marcelgmr strcpy(dstpath, CWD);
667 0ea64589 2014-11-14 marcelgmr strcat(dstpath, srcpath + strlen(rover.marks.dirpath));
668 8a757b0f 2015-03-07 marcelgmr ret = rename(srcpath, dstpath);
669 8a757b0f 2015-03-07 marcelgmr if (ret < 0 && errno == EXDEV) {
670 8a757b0f 2015-03-07 marcelgmr ret = cpyfile(srcpath);
671 8a757b0f 2015-03-07 marcelgmr if (ret < 0) return ret;
672 8a757b0f 2015-03-07 marcelgmr ret = delfile(srcpath);
673 8a757b0f 2015-03-07 marcelgmr }
674 8a757b0f 2015-03-07 marcelgmr return ret;
675 b7ee4ee2 2014-11-14 marcelgmr }
676 b7ee4ee2 2014-11-14 marcelgmr
677 a022230d 2015-04-26 marcelgmr static void
678 a022230d 2015-04-26 marcelgmr start_line_edit(const char *init_input)
679 411ec846 2014-11-08 marcelgmr {
680 d5fe31b0 2014-11-14 marcelgmr curs_set(TRUE);
681 a022230d 2015-04-26 marcelgmr strncpy(INPUT, init_input, INPUTSZ);
682 6110e5a1 2015-04-26 marcelgmr strncpy(rover.edit.buffer, init_input, INPUTSZ);
683 a022230d 2015-04-26 marcelgmr rover.edit.left = strlen(init_input);
684 6110e5a1 2015-04-26 marcelgmr rover.edit.right = INPUTSZ - 1;
685 6998a035 2015-05-31 marcelgmr rover.edit_scroll = 0;
686 a022230d 2015-04-26 marcelgmr }
687 a022230d 2015-04-26 marcelgmr
688 a022230d 2015-04-26 marcelgmr /* Read input and change editing state accordingly. */
689 a022230d 2015-04-26 marcelgmr static EditStat
690 a022230d 2015-04-26 marcelgmr get_line_edit()
691 a022230d 2015-04-26 marcelgmr {
692 a022230d 2015-04-26 marcelgmr int ch = getch();
693 a022230d 2015-04-26 marcelgmr if (ch == '\r' || ch == '\n' || ch == KEY_ENTER) {
694 d5fe31b0 2014-11-14 marcelgmr curs_set(FALSE);
695 a022230d 2015-04-26 marcelgmr return CONFIRM;
696 a022230d 2015-04-26 marcelgmr } else if (ch == '\t') {
697 a022230d 2015-04-26 marcelgmr curs_set(FALSE);
698 a022230d 2015-04-26 marcelgmr return CANCEL;
699 a022230d 2015-04-26 marcelgmr } else if (EDIT_CAN_LEFT(rover.edit) && ch == KEY_LEFT) {
700 a022230d 2015-04-26 marcelgmr EDIT_LEFT(rover.edit);
701 a022230d 2015-04-26 marcelgmr } else if (EDIT_CAN_RIGHT(rover.edit) && ch == KEY_RIGHT) {
702 a022230d 2015-04-26 marcelgmr EDIT_RIGHT(rover.edit);
703 a022230d 2015-04-26 marcelgmr } else if (ch == KEY_UP) {
704 a022230d 2015-04-26 marcelgmr while (EDIT_CAN_LEFT(rover.edit)) EDIT_LEFT(rover.edit);
705 a022230d 2015-04-26 marcelgmr } else if (ch == KEY_DOWN) {
706 a022230d 2015-04-26 marcelgmr while (EDIT_CAN_RIGHT(rover.edit)) EDIT_RIGHT(rover.edit);
707 a022230d 2015-04-26 marcelgmr } else if (ch == erasechar() || ch == KEY_BACKSPACE) {
708 a022230d 2015-04-26 marcelgmr if (EDIT_CAN_LEFT(rover.edit)) EDIT_BACKSPACE(rover.edit);
709 a022230d 2015-04-26 marcelgmr } else if (ch == KEY_DC) {
710 a022230d 2015-04-26 marcelgmr if (EDIT_CAN_RIGHT(rover.edit)) EDIT_DELETE(rover.edit);
711 a022230d 2015-04-26 marcelgmr } else if (ch == killchar()) {
712 a022230d 2015-04-26 marcelgmr EDIT_CLEAR(rover.edit);
713 a022230d 2015-04-26 marcelgmr clear_message();
714 a022230d 2015-04-26 marcelgmr } else if (!EDIT_FULL(rover.edit) && isprint(ch)) {
715 a022230d 2015-04-26 marcelgmr EDIT_INSERT(rover.edit, ch);
716 411ec846 2014-11-08 marcelgmr }
717 a022230d 2015-04-26 marcelgmr /* Copy edit contents to INPUT and append null character. */
718 6110e5a1 2015-04-26 marcelgmr strncpy(INPUT, rover.edit.buffer, rover.edit.left);
719 a022230d 2015-04-26 marcelgmr strncpy(&INPUT[rover.edit.left], &rover.edit.buffer[rover.edit.right+1],
720 6110e5a1 2015-04-26 marcelgmr INPUTSZ-rover.edit.left-1);
721 6110e5a1 2015-04-26 marcelgmr INPUT[rover.edit.left+INPUTSZ-rover.edit.right-1] = '\0';
722 a022230d 2015-04-26 marcelgmr return CONTINUE;
723 743e70b8 2014-11-14 marcelgmr }
724 743e70b8 2014-11-14 marcelgmr
725 5c4a6b62 2014-11-14 marcelgmr /* Update line input on the screen. */
726 743e70b8 2014-11-14 marcelgmr static void
727 eef51ac5 2015-03-24 marcelgmr update_input(char *prompt, Color color)
728 743e70b8 2014-11-14 marcelgmr {
729 6998a035 2015-05-31 marcelgmr int plen, ilen, maxlen;
730 743e70b8 2014-11-14 marcelgmr
731 743e70b8 2014-11-14 marcelgmr plen = strlen(prompt);
732 743e70b8 2014-11-14 marcelgmr ilen = strlen(INPUT);
733 6998a035 2015-05-31 marcelgmr maxlen = STATUSPOS - plen - 2;
734 6998a035 2015-05-31 marcelgmr if (ilen - rover.edit_scroll < maxlen)
735 6998a035 2015-05-31 marcelgmr rover.edit_scroll = MAX(ilen - maxlen, 0);
736 6998a035 2015-05-31 marcelgmr else if (rover.edit.left > rover.edit_scroll + maxlen - 1)
737 6998a035 2015-05-31 marcelgmr rover.edit_scroll = rover.edit.left - maxlen;
738 6998a035 2015-05-31 marcelgmr else if (rover.edit.left < rover.edit_scroll)
739 6998a035 2015-05-31 marcelgmr rover.edit_scroll = MAX(rover.edit.left - maxlen, 0);
740 743e70b8 2014-11-14 marcelgmr color_set(RVC_PROMPT, NULL);
741 743e70b8 2014-11-14 marcelgmr mvaddstr(LINES - 1, 0, prompt);
742 743e70b8 2014-11-14 marcelgmr color_set(color, NULL);
743 6998a035 2015-05-31 marcelgmr mvaddnstr(LINES - 1, plen, &INPUT[rover.edit_scroll], maxlen);
744 6998a035 2015-05-31 marcelgmr mvaddch(LINES - 1, plen + MIN(ilen - rover.edit_scroll, maxlen + 1), ' ');
745 743e70b8 2014-11-14 marcelgmr color_set(DEFAULT, NULL);
746 33fb6e3a 2015-05-31 marcelgmr if (rover.edit_scroll)
747 33fb6e3a 2015-05-31 marcelgmr mvaddch(LINES - 1, plen - 1, '<');
748 33fb6e3a 2015-05-31 marcelgmr if (ilen > rover.edit_scroll + maxlen)
749 33fb6e3a 2015-05-31 marcelgmr mvaddch(LINES - 1, plen + maxlen, '>');
750 33fb6e3a 2015-05-31 marcelgmr move(LINES - 1, plen + rover.edit.left - rover.edit_scroll);
751 e1c42cfe 2014-11-11 marcelgmr }
752 e1c42cfe 2014-11-11 marcelgmr
753 71ee1627 2014-11-07 marcelgmr int
754 38a357b6 2014-11-09 marcelgmr main(int argc, char *argv[])
755 71ee1627 2014-11-07 marcelgmr {
756 ada8fba9 2014-11-09 marcelgmr int i, ch;
757 14b5cd28 2015-01-06 marcelgmr char *program;
758 14b5cd28 2015-01-06 marcelgmr const char *key;
759 38a357b6 2014-11-09 marcelgmr DIR *d;
760 a022230d 2015-04-26 marcelgmr EditStat edit_stat;
761 71ee1627 2014-11-07 marcelgmr
762 ff684771 2014-12-02 marcelgmr if (argc == 2) {
763 ff684771 2014-12-02 marcelgmr if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) {
764 ff684771 2014-12-02 marcelgmr printf("rover %s\n", RV_VERSION);
765 ff684771 2014-12-02 marcelgmr return 0;
766 ff684771 2014-12-02 marcelgmr } else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
767 ff684771 2014-12-02 marcelgmr printf(
768 ff684771 2014-12-02 marcelgmr "Usage: rover [DIRECTORY [DIRECTORY [DIRECTORY [...]]]]\n"
769 ff684771 2014-12-02 marcelgmr " or: rover [OPTION]\n"
770 ff684771 2014-12-02 marcelgmr "Browse current working directory or the ones specified.\n\n"
771 ff684771 2014-12-02 marcelgmr "Options:\n"
772 ff684771 2014-12-02 marcelgmr " -h, --help print this help message and exit\n"
773 ff684771 2014-12-02 marcelgmr " -v, --version print program version and exit\n\n"
774 ff684771 2014-12-02 marcelgmr "See rover(1) for more information.\n\n"
775 ff684771 2014-12-02 marcelgmr "Rover homepage: <https://github.com/lecram/rover>.\n"
776 ff684771 2014-12-02 marcelgmr );
777 ff684771 2014-12-02 marcelgmr return 0;
778 ff684771 2014-12-02 marcelgmr }
779 ff684771 2014-12-02 marcelgmr }
780 f05efd9e 2014-11-07 marcelgmr init_term();
781 f05efd9e 2014-11-07 marcelgmr rover.nfiles = 0;
782 47e9f26d 2014-11-09 marcelgmr for (i = 0; i < 10; i++) {
783 7c74df90 2014-11-15 marcelgmr rover.esel[i] = rover.scroll[i] = 0;
784 47e9f26d 2014-11-09 marcelgmr rover.flags[i] = SHOW_FILES | SHOW_DIRS;
785 47e9f26d 2014-11-09 marcelgmr }
786 ada8fba9 2014-11-09 marcelgmr strcpy(rover.cwd[0], getenv("HOME"));
787 38a357b6 2014-11-09 marcelgmr for (i = 1; i < argc && i < 10; i++) {
788 7c74df90 2014-11-15 marcelgmr if ((d = opendir(argv[i]))) {
789 c04b0d89 2015-03-30 marcelgmr realpath(argv[i], rover.cwd[i]);
790 38a357b6 2014-11-09 marcelgmr closedir(d);
791 590d39af 2014-12-02 marcelgmr } else
792 590d39af 2014-12-02 marcelgmr strcpy(rover.cwd[i], rover.cwd[0]);
793 38a357b6 2014-11-09 marcelgmr }
794 c04b0d89 2015-03-30 marcelgmr getcwd(rover.cwd[i], PATH_MAX);
795 38a357b6 2014-11-09 marcelgmr for (i++; i < 10; i++)
796 38a357b6 2014-11-09 marcelgmr strcpy(rover.cwd[i], rover.cwd[i-1]);
797 38a357b6 2014-11-09 marcelgmr for (i = 0; i < 10; i++)
798 38a357b6 2014-11-09 marcelgmr if (rover.cwd[i][strlen(rover.cwd[i]) - 1] != '/')
799 38a357b6 2014-11-09 marcelgmr strcat(rover.cwd[i], "/");
800 ada8fba9 2014-11-09 marcelgmr rover.tab = 1;
801 ada8fba9 2014-11-09 marcelgmr rover.window = subwin(stdscr, LINES - 2, COLS, 1, 0);
802 18016333 2014-11-14 marcelgmr init_marks(&rover.marks);
803 ada8fba9 2014-11-09 marcelgmr cd(1);
804 0b301167 2014-11-07 marcelgmr while (1) {
805 ada8fba9 2014-11-09 marcelgmr ch = getch();
806 ada8fba9 2014-11-09 marcelgmr key = keyname(ch);
807 865c9839 2014-11-15 marcelgmr clear_message();
808 a31a7b29 2014-11-15 marcelgmr if (!strcmp(key, RVK_QUIT)) break;
809 ada8fba9 2014-11-09 marcelgmr else if (ch >= '0' && ch <= '9') {
810 ada8fba9 2014-11-09 marcelgmr rover.tab = ch - '0';
811 ada8fba9 2014-11-09 marcelgmr cd(0);
812 ff684771 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_HELP)) {
813 ff684771 2014-12-02 marcelgmr ARGS[0] = "man";
814 ff684771 2014-12-02 marcelgmr ARGS[1] = "rover";
815 ff684771 2014-12-02 marcelgmr ARGS[2] = NULL;
816 ff684771 2014-12-02 marcelgmr spawn();
817 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_DOWN)) {
818 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles) continue;
819 7c74df90 2014-11-15 marcelgmr ESEL = (ESEL + 1) % rover.nfiles;
820 743e70b8 2014-11-14 marcelgmr update_view();
821 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_UP)) {
822 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles) continue;
823 7c74df90 2014-11-15 marcelgmr ESEL = ESEL ? ESEL - 1 : rover.nfiles - 1;
824 743e70b8 2014-11-14 marcelgmr update_view();
825 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_JUMP_DOWN)) {
826 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles) continue;
827 60128fcd 2014-11-15 marcelgmr ESEL = MIN(ESEL + RV_JUMP, rover.nfiles - 1);
828 60128fcd 2014-11-15 marcelgmr if (rover.nfiles > HEIGHT)
829 60128fcd 2014-11-15 marcelgmr SCROLL = MIN(SCROLL + RV_JUMP, rover.nfiles - HEIGHT);
830 743e70b8 2014-11-14 marcelgmr update_view();
831 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_JUMP_UP)) {
832 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles) continue;
833 60128fcd 2014-11-15 marcelgmr ESEL = MAX(ESEL - RV_JUMP, 0);
834 60128fcd 2014-11-15 marcelgmr SCROLL = MAX(SCROLL - RV_JUMP, 0);
835 743e70b8 2014-11-14 marcelgmr update_view();
836 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_CD_DOWN)) {
837 7c74df90 2014-11-15 marcelgmr if (!rover.nfiles || !ISDIR(ENAME(ESEL))) continue;
838 7c74df90 2014-11-15 marcelgmr strcat(CWD, ENAME(ESEL));
839 ada8fba9 2014-11-09 marcelgmr cd(1);
840 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_CD_UP)) {
841 45020106 2014-11-08 marcelgmr char *dirname, first;
842 58fbefc5 2014-11-19 marcelgmr if (!strcmp(CWD, "/")) continue;
843 ada8fba9 2014-11-09 marcelgmr CWD[strlen(CWD) - 1] = '\0';
844 ada8fba9 2014-11-09 marcelgmr dirname = strrchr(CWD, '/') + 1;
845 45020106 2014-11-08 marcelgmr first = dirname[0];
846 45020106 2014-11-08 marcelgmr dirname[0] = '\0';
847 ada8fba9 2014-11-09 marcelgmr cd(1);
848 430cd7d8 2014-11-19 marcelgmr dirname[0] = first;
849 430cd7d8 2014-11-19 marcelgmr dirname[strlen(dirname)] = '/';
850 430cd7d8 2014-11-19 marcelgmr try_to_sel(dirname);
851 430cd7d8 2014-11-19 marcelgmr dirname[0] = '\0';
852 430cd7d8 2014-11-19 marcelgmr update_view();
853 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_HOME)) {
854 ada8fba9 2014-11-09 marcelgmr strcpy(CWD, getenv("HOME"));
855 ada8fba9 2014-11-09 marcelgmr if (CWD[strlen(CWD) - 1] != '/')
856 ada8fba9 2014-11-09 marcelgmr strcat(CWD, "/");
857 ada8fba9 2014-11-09 marcelgmr cd(1);
858 97217d57 2015-05-26 marcelgmr } else if (!strcmp(key, RVK_REFRESH)) {
859 97217d57 2015-05-26 marcelgmr reload();
860 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_SHELL)) {
861 71ee1627 2014-11-07 marcelgmr program = getenv("SHELL");
862 71ee1627 2014-11-07 marcelgmr if (program) {
863 3cd6bb98 2014-11-11 marcelgmr ARGS[0] = program;
864 3cd6bb98 2014-11-11 marcelgmr ARGS[1] = NULL;
865 71ee1627 2014-11-07 marcelgmr spawn();
866 00ecdc1e 2014-11-19 marcelgmr reload();
867 71ee1627 2014-11-07 marcelgmr }
868 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_VIEW)) {
869 7c74df90 2014-11-15 marcelgmr if (!rover.nfiles || ISDIR(ENAME(ESEL))) continue;
870 4b66a2c4 2014-11-07 marcelgmr program = getenv("PAGER");
871 4b66a2c4 2014-11-07 marcelgmr if (program) {
872 3cd6bb98 2014-11-11 marcelgmr ARGS[0] = program;
873 7c74df90 2014-11-15 marcelgmr ARGS[1] = ENAME(ESEL);
874 3cd6bb98 2014-11-11 marcelgmr ARGS[2] = NULL;
875 4b66a2c4 2014-11-07 marcelgmr spawn();
876 4b66a2c4 2014-11-07 marcelgmr }
877 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_EDIT)) {
878 7c74df90 2014-11-15 marcelgmr if (!rover.nfiles || ISDIR(ENAME(ESEL))) continue;
879 71ee1627 2014-11-07 marcelgmr program = getenv("EDITOR");
880 71ee1627 2014-11-07 marcelgmr if (program) {
881 3cd6bb98 2014-11-11 marcelgmr ARGS[0] = program;
882 7c74df90 2014-11-15 marcelgmr ARGS[1] = ENAME(ESEL);
883 3cd6bb98 2014-11-11 marcelgmr ARGS[2] = NULL;
884 71ee1627 2014-11-07 marcelgmr spawn();
885 39ee8f33 2014-11-14 marcelgmr cd(0);
886 71ee1627 2014-11-07 marcelgmr }
887 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_SEARCH)) {
888 1447784d 2014-11-14 marcelgmr int oldsel, oldscroll, length;
889 743e70b8 2014-11-14 marcelgmr char *prompt = "search: ";
890 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles) continue;
891 7c74df90 2014-11-15 marcelgmr oldsel = ESEL;
892 ada8fba9 2014-11-09 marcelgmr oldscroll = SCROLL;
893 a022230d 2015-04-26 marcelgmr start_line_edit("");
894 743e70b8 2014-11-14 marcelgmr update_input(prompt, DEFAULT);
895 a022230d 2015-04-26 marcelgmr while ((edit_stat = get_line_edit()) == CONTINUE) {
896 1447784d 2014-11-14 marcelgmr int sel;
897 eef51ac5 2015-03-24 marcelgmr Color color = RED;
898 1447784d 2014-11-14 marcelgmr length = strlen(INPUT);
899 a17e36e3 2014-11-07 marcelgmr if (length) {
900 f05efd9e 2014-11-07 marcelgmr for (sel = 0; sel < rover.nfiles; sel++)
901 7c74df90 2014-11-15 marcelgmr if (!strncmp(ENAME(sel), INPUT, length))
902 a17e36e3 2014-11-07 marcelgmr break;
903 f05efd9e 2014-11-07 marcelgmr if (sel < rover.nfiles) {
904 a17e36e3 2014-11-07 marcelgmr color = GREEN;
905 7c74df90 2014-11-15 marcelgmr ESEL = sel;
906 f05efd9e 2014-11-07 marcelgmr if (rover.nfiles > HEIGHT) {
907 89cfd83b 2014-11-08 marcelgmr if (sel < 3)
908 ada8fba9 2014-11-09 marcelgmr SCROLL = 0;
909 89cfd83b 2014-11-08 marcelgmr else if (sel - 3 > rover.nfiles - HEIGHT)
910 ada8fba9 2014-11-09 marcelgmr SCROLL = rover.nfiles - HEIGHT;
911 a17e36e3 2014-11-07 marcelgmr else
912 ada8fba9 2014-11-09 marcelgmr SCROLL = sel - 3;
913 a17e36e3 2014-11-07 marcelgmr }
914 a17e36e3 2014-11-07 marcelgmr }
915 590d39af 2014-12-02 marcelgmr } else {
916 7c74df90 2014-11-15 marcelgmr ESEL = oldsel;
917 ada8fba9 2014-11-09 marcelgmr SCROLL = oldscroll;
918 411ec846 2014-11-08 marcelgmr }
919 743e70b8 2014-11-14 marcelgmr update_view();
920 743e70b8 2014-11-14 marcelgmr update_input(prompt, color);
921 a17e36e3 2014-11-07 marcelgmr }
922 a022230d 2015-04-26 marcelgmr if (edit_stat == CANCEL) {
923 a022230d 2015-04-26 marcelgmr ESEL = oldsel;
924 a022230d 2015-04-26 marcelgmr SCROLL = oldscroll;
925 a022230d 2015-04-26 marcelgmr }
926 865c9839 2014-11-15 marcelgmr clear_message();
927 743e70b8 2014-11-14 marcelgmr update_view();
928 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_TG_FILES)) {
929 47e9f26d 2014-11-09 marcelgmr FLAGS ^= SHOW_FILES;
930 00ecdc1e 2014-11-19 marcelgmr reload();
931 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_TG_DIRS)) {
932 47e9f26d 2014-11-09 marcelgmr FLAGS ^= SHOW_DIRS;
933 00ecdc1e 2014-11-19 marcelgmr reload();
934 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_TG_HIDDEN)) {
935 47e9f26d 2014-11-09 marcelgmr FLAGS ^= SHOW_HIDDEN;
936 00ecdc1e 2014-11-19 marcelgmr reload();
937 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_NEW_FILE)) {
938 743e70b8 2014-11-14 marcelgmr int ok = 0;
939 743e70b8 2014-11-14 marcelgmr char *prompt = "new file: ";
940 a022230d 2015-04-26 marcelgmr start_line_edit("");
941 743e70b8 2014-11-14 marcelgmr update_input(prompt, DEFAULT);
942 a022230d 2015-04-26 marcelgmr while ((edit_stat = get_line_edit()) == CONTINUE) {
943 ddbe9d62 2014-11-14 marcelgmr int length = strlen(INPUT);
944 1447784d 2014-11-14 marcelgmr ok = 1;
945 e444d3b1 2014-11-14 marcelgmr for (i = 0; i < rover.nfiles; i++) {
946 ddbe9d62 2014-11-14 marcelgmr if (
947 7c74df90 2014-11-15 marcelgmr !strncmp(ENAME(i), INPUT, length) &&
948 7c74df90 2014-11-15 marcelgmr (!strcmp(ENAME(i) + length, "") ||
949 7c74df90 2014-11-15 marcelgmr !strcmp(ENAME(i) + length, "/"))
950 ddbe9d62 2014-11-14 marcelgmr ) {
951 1447784d 2014-11-14 marcelgmr ok = 0;
952 1447784d 2014-11-14 marcelgmr break;
953 1447784d 2014-11-14 marcelgmr }
954 e444d3b1 2014-11-14 marcelgmr }
955 743e70b8 2014-11-14 marcelgmr update_input(prompt, ok ? GREEN : RED);
956 1447784d 2014-11-14 marcelgmr }
957 865c9839 2014-11-15 marcelgmr clear_message();
958 a022230d 2015-04-26 marcelgmr if (edit_stat == CONFIRM && strlen(INPUT)) {
959 430cd7d8 2014-11-19 marcelgmr if (ok) {
960 430cd7d8 2014-11-19 marcelgmr addfile(INPUT);
961 430cd7d8 2014-11-19 marcelgmr cd(1);
962 430cd7d8 2014-11-19 marcelgmr try_to_sel(INPUT);
963 430cd7d8 2014-11-19 marcelgmr update_view();
964 590d39af 2014-12-02 marcelgmr } else
965 590d39af 2014-12-02 marcelgmr message("File already exists.", RED);
966 1447784d 2014-11-14 marcelgmr }
967 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_NEW_DIR)) {
968 743e70b8 2014-11-14 marcelgmr int ok = 0;
969 743e70b8 2014-11-14 marcelgmr char *prompt = "new directory: ";
970 a022230d 2015-04-26 marcelgmr start_line_edit("");
971 743e70b8 2014-11-14 marcelgmr update_input(prompt, DEFAULT);
972 a022230d 2015-04-26 marcelgmr while ((edit_stat = get_line_edit()) == CONTINUE) {
973 ddbe9d62 2014-11-14 marcelgmr int length = strlen(INPUT);
974 1447784d 2014-11-14 marcelgmr ok = 1;
975 e444d3b1 2014-11-14 marcelgmr for (i = 0; i < rover.nfiles; i++) {
976 ddbe9d62 2014-11-14 marcelgmr if (
977 7c74df90 2014-11-15 marcelgmr !strncmp(ENAME(i), INPUT, length) &&
978 7c74df90 2014-11-15 marcelgmr (!strcmp(ENAME(i) + length, "") ||
979 7c74df90 2014-11-15 marcelgmr !strcmp(ENAME(i) + length, "/"))
980 ddbe9d62 2014-11-14 marcelgmr ) {
981 1447784d 2014-11-14 marcelgmr ok = 0;
982 1447784d 2014-11-14 marcelgmr break;
983 1447784d 2014-11-14 marcelgmr }
984 e444d3b1 2014-11-14 marcelgmr }
985 743e70b8 2014-11-14 marcelgmr update_input(prompt, ok ? GREEN : RED);
986 1447784d 2014-11-14 marcelgmr }
987 865c9839 2014-11-15 marcelgmr clear_message();
988 a022230d 2015-04-26 marcelgmr if (edit_stat == CONFIRM && strlen(INPUT)) {
989 430cd7d8 2014-11-19 marcelgmr if (ok) {
990 430cd7d8 2014-11-19 marcelgmr adddir(INPUT);
991 430cd7d8 2014-11-19 marcelgmr cd(1);
992 430cd7d8 2014-11-19 marcelgmr try_to_sel(INPUT);
993 430cd7d8 2014-11-19 marcelgmr update_view();
994 590d39af 2014-12-02 marcelgmr } else
995 590d39af 2014-12-02 marcelgmr message("File already exists.", RED);
996 1447784d 2014-11-14 marcelgmr }
997 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_RENAME)) {
998 bdb195d0 2014-11-14 marcelgmr int ok = 0;
999 bdb195d0 2014-11-14 marcelgmr char *prompt = "rename: ";
1000 f499f7c7 2014-12-03 marcelgmr char *last;
1001 f499f7c7 2014-12-03 marcelgmr int isdir;
1002 7c74df90 2014-11-15 marcelgmr strcpy(INPUT, ENAME(ESEL));
1003 f499f7c7 2014-12-03 marcelgmr last = INPUT + strlen(INPUT) - 1;
1004 f499f7c7 2014-12-03 marcelgmr if ((isdir = *last == '/'))
1005 f499f7c7 2014-12-03 marcelgmr *last = '\0';
1006 a022230d 2015-04-26 marcelgmr start_line_edit(INPUT);
1007 ddbe9d62 2014-11-14 marcelgmr update_input(prompt, RED);
1008 a022230d 2015-04-26 marcelgmr while ((edit_stat = get_line_edit()) == CONTINUE) {
1009 ddbe9d62 2014-11-14 marcelgmr int length = strlen(INPUT);
1010 bdb195d0 2014-11-14 marcelgmr ok = 1;
1011 5f047452 2014-12-03 marcelgmr for (i = 0; i < rover.nfiles; i++)
1012 ddbe9d62 2014-11-14 marcelgmr if (
1013 7c74df90 2014-11-15 marcelgmr !strncmp(ENAME(i), INPUT, length) &&
1014 7c74df90 2014-11-15 marcelgmr (!strcmp(ENAME(i) + length, "") ||
1015 7c74df90 2014-11-15 marcelgmr !strcmp(ENAME(i) + length, "/"))
1016 ddbe9d62 2014-11-14 marcelgmr ) {
1017 bdb195d0 2014-11-14 marcelgmr ok = 0;
1018 bdb195d0 2014-11-14 marcelgmr break;
1019 bdb195d0 2014-11-14 marcelgmr }
1020 bdb195d0 2014-11-14 marcelgmr update_input(prompt, ok ? GREEN : RED);
1021 bdb195d0 2014-11-14 marcelgmr }
1022 865c9839 2014-11-15 marcelgmr clear_message();
1023 a022230d 2015-04-26 marcelgmr if (edit_stat == CONFIRM && strlen(INPUT)) {
1024 f499f7c7 2014-12-03 marcelgmr if (isdir)
1025 f499f7c7 2014-12-03 marcelgmr strcat(INPUT, "/");
1026 00ecdc1e 2014-11-19 marcelgmr if (ok) {
1027 dbb53e68 2014-12-03 marcelgmr if (!rename(ENAME(ESEL), INPUT) && MARKED(ESEL)) {
1028 dbb53e68 2014-12-03 marcelgmr del_mark(&rover.marks, ENAME(ESEL));
1029 dbb53e68 2014-12-03 marcelgmr add_mark(&rover.marks, CWD, INPUT);
1030 dbb53e68 2014-12-03 marcelgmr }
1031 00ecdc1e 2014-11-19 marcelgmr cd(1);
1032 00ecdc1e 2014-11-19 marcelgmr try_to_sel(INPUT);
1033 00ecdc1e 2014-11-19 marcelgmr update_view();
1034 590d39af 2014-12-02 marcelgmr } else
1035 590d39af 2014-12-02 marcelgmr message("File already exists.", RED);
1036 bdb195d0 2014-11-14 marcelgmr }
1037 e0d6077a 2015-05-27 marcelgmr } else if (!strcmp(key, RVK_DELETE)) {
1038 e0d6077a 2015-05-27 marcelgmr if (rover.nfiles) {
1039 e0d6077a 2015-05-27 marcelgmr message("Delete selected entry? (Y to confirm)", YELLOW);
1040 e0d6077a 2015-05-27 marcelgmr if (getch() == 'Y') {
1041 e0d6077a 2015-05-27 marcelgmr const char *name = ENAME(ESEL);
1042 e0d6077a 2015-05-27 marcelgmr int ret = ISDIR(name) ? deldir(name) : delfile(name);
1043 e0d6077a 2015-05-27 marcelgmr reload();
1044 e0d6077a 2015-05-27 marcelgmr if (ret)
1045 e0d6077a 2015-05-27 marcelgmr message("Could not delete entry.", RED);
1046 e0d6077a 2015-05-27 marcelgmr } else
1047 e0d6077a 2015-05-27 marcelgmr clear_message();
1048 e0d6077a 2015-05-27 marcelgmr } else
1049 e0d6077a 2015-05-27 marcelgmr message("No entry selected for deletion.", RED);
1050 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_TG_MARK)) {
1051 7c74df90 2014-11-15 marcelgmr if (MARKED(ESEL))
1052 7c74df90 2014-11-15 marcelgmr del_mark(&rover.marks, ENAME(ESEL));
1053 18016333 2014-11-14 marcelgmr else
1054 7c74df90 2014-11-15 marcelgmr add_mark(&rover.marks, CWD, ENAME(ESEL));
1055 7c74df90 2014-11-15 marcelgmr MARKED(ESEL) = !MARKED(ESEL);
1056 7c74df90 2014-11-15 marcelgmr ESEL = (ESEL + 1) % rover.nfiles;
1057 743e70b8 2014-11-14 marcelgmr update_view();
1058 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_INVMARK)) {
1059 5fc8b927 2014-11-14 marcelgmr for (i = 0; i < rover.nfiles; i++) {
1060 5fc8b927 2014-11-14 marcelgmr if (MARKED(i))
1061 7c74df90 2014-11-15 marcelgmr del_mark(&rover.marks, ENAME(i));
1062 5fc8b927 2014-11-14 marcelgmr else
1063 7c74df90 2014-11-15 marcelgmr add_mark(&rover.marks, CWD, ENAME(i));
1064 5fc8b927 2014-11-14 marcelgmr MARKED(i) = !MARKED(i);
1065 5fc8b927 2014-11-14 marcelgmr }
1066 743e70b8 2014-11-14 marcelgmr update_view();
1067 590d39af 2014-12-02 marcelgmr } else if (!strcmp(key, RVK_MARKALL)) {
1068 5fc8b927 2014-11-14 marcelgmr for (i = 0; i < rover.nfiles; i++)
1069 5fc8b927 2014-11-14 marcelgmr if (!MARKED(i)) {
1070 7c74df90 2014-11-15 marcelgmr add_mark(&rover.marks, CWD, ENAME(i));
1071 5fc8b927 2014-11-14 marcelgmr MARKED(i) = 1;
1072 5fc8b927 2014-11-14 marcelgmr }
1073 743e70b8 2014-11-14 marcelgmr update_view();
1074 e0d6077a 2015-05-27 marcelgmr } else if (!strcmp(key, RVK_MARK_DELETE)) {
1075 a31a7b29 2014-11-15 marcelgmr if (rover.marks.nentries) {
1076 a31a7b29 2014-11-15 marcelgmr message("Delete marked entries? (Y to confirm)", YELLOW);
1077 a31a7b29 2014-11-15 marcelgmr if (getch() == 'Y')
1078 a31a7b29 2014-11-15 marcelgmr process_marked(NULL, delfile, deldir);
1079 590d39af 2014-12-02 marcelgmr else
1080 590d39af 2014-12-02 marcelgmr clear_message();
1081 590d39af 2014-12-02 marcelgmr } else
1082 590d39af 2014-12-02 marcelgmr message("No entries marked for deletion.", RED);
1083 e0d6077a 2015-05-27 marcelgmr } else if (!strcmp(key, RVK_MARK_COPY)) {
1084 a31a7b29 2014-11-15 marcelgmr if (rover.marks.nentries)
1085 a31a7b29 2014-11-15 marcelgmr process_marked(adddir, cpyfile, NULL);
1086 590d39af 2014-12-02 marcelgmr else
1087 590d39af 2014-12-02 marcelgmr message("No entries marked for copying.", RED);
1088 e0d6077a 2015-05-27 marcelgmr } else if (!strcmp(key, RVK_MARK_MOVE)) {
1089 a31a7b29 2014-11-15 marcelgmr if (rover.marks.nentries)
1090 a31a7b29 2014-11-15 marcelgmr process_marked(adddir, movfile, deldir);
1091 590d39af 2014-12-02 marcelgmr else
1092 590d39af 2014-12-02 marcelgmr message("No entries marked for moving.", RED);
1093 a31a7b29 2014-11-15 marcelgmr }
1094 576e768d 2014-11-08 marcelgmr }
1095 18016333 2014-11-14 marcelgmr if (rover.nfiles)
1096 18016333 2014-11-14 marcelgmr free_rows(&rover.rows, rover.nfiles);
1097 c3758004 2014-11-15 marcelgmr free_marks(&rover.marks);
1098 f05efd9e 2014-11-07 marcelgmr delwin(rover.window);
1099 71ee1627 2014-11-07 marcelgmr return 0;
1100 71ee1627 2014-11-07 marcelgmr }