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 71ee1627 2014-11-07 marcelgmr #include <stdio.h> /* FILENAME_MAX */
7 71ee1627 2014-11-07 marcelgmr #include <locale.h> /* setlocale(), LC_ALL */
8 b7ee4ee2 2014-11-14 marcelgmr #include <unistd.h> /* chdir(), getcwd(), read(), close(), ... */
9 71ee1627 2014-11-07 marcelgmr #include <dirent.h> /* DIR, struct dirent, opendir(), ... */
10 71ee1627 2014-11-07 marcelgmr #include <sys/stat.h>
11 b7ee4ee2 2014-11-14 marcelgmr #include <fcntl.h> /* open() */
12 71ee1627 2014-11-07 marcelgmr #include <sys/wait.h> /* waitpid() */
13 b529416b 2014-11-11 marcelgmr #include <signal.h> /* struct sigaction, sigaction() */
14 71ee1627 2014-11-07 marcelgmr #include <curses.h>
15 71ee1627 2014-11-07 marcelgmr
16 71ee1627 2014-11-07 marcelgmr #include "config.h"
17 71ee1627 2014-11-07 marcelgmr
18 3cd6bb98 2014-11-11 marcelgmr /* String buffers. */
19 576e768d 2014-11-08 marcelgmr #define ROWSZ 256
20 3cd6bb98 2014-11-11 marcelgmr static char ROW[ROWSZ];
21 a17e36e3 2014-11-07 marcelgmr #define STATUSSZ 256
22 3cd6bb98 2014-11-11 marcelgmr static char STATUS[STATUSSZ];
23 1447784d 2014-11-14 marcelgmr #define INPUTSZ 256
24 1447784d 2014-11-14 marcelgmr static char INPUT[INPUTSZ];
25 3cd6bb98 2014-11-11 marcelgmr
26 3cd6bb98 2014-11-11 marcelgmr /* Argument buffers for execvp(). */
27 71ee1627 2014-11-07 marcelgmr #define MAXARGS 256
28 3cd6bb98 2014-11-11 marcelgmr static char *ARGS[MAXARGS];
29 71ee1627 2014-11-07 marcelgmr
30 60128fcd 2014-11-15 marcelgmr /* Listing view parameters. */
31 60128fcd 2014-11-15 marcelgmr #define HEIGHT (LINES-4)
32 60128fcd 2014-11-15 marcelgmr #define STATUSPOS (COLS-16)
33 f05efd9e 2014-11-07 marcelgmr
34 3cd6bb98 2014-11-11 marcelgmr /* Listing view flags. */
35 bae1431c 2014-11-07 marcelgmr #define SHOW_FILES 0x01u
36 bae1431c 2014-11-07 marcelgmr #define SHOW_DIRS 0x02u
37 bae1431c 2014-11-07 marcelgmr #define SHOW_HIDDEN 0x04u
38 bae1431c 2014-11-07 marcelgmr
39 50c63039 2014-11-14 marcelgmr /* Marks parameters. */
40 18016333 2014-11-14 marcelgmr #define BULK_INIT 5
41 18016333 2014-11-14 marcelgmr #define BULK_THRESH 256
42 18016333 2014-11-14 marcelgmr
43 3cd6bb98 2014-11-11 marcelgmr /* Information associated to each entry in listing. */
44 576e768d 2014-11-08 marcelgmr typedef struct {
45 576e768d 2014-11-08 marcelgmr char *name;
46 576e768d 2014-11-08 marcelgmr off_t size;
47 18016333 2014-11-14 marcelgmr int marked;
48 576e768d 2014-11-08 marcelgmr } row_t;
49 576e768d 2014-11-08 marcelgmr
50 5c4a6b62 2014-11-14 marcelgmr /* Dynamic array of marked entries. */
51 18016333 2014-11-14 marcelgmr typedef struct {
52 18016333 2014-11-14 marcelgmr char dirpath[FILENAME_MAX];
53 18016333 2014-11-14 marcelgmr int bulk;
54 18016333 2014-11-14 marcelgmr int nentries;
55 18016333 2014-11-14 marcelgmr char **entries;
56 18016333 2014-11-14 marcelgmr } marks_t;
57 18016333 2014-11-14 marcelgmr
58 3cd6bb98 2014-11-11 marcelgmr /* Global state. Some basic info is allocated for ten tabs. */
59 d06e977d 2014-11-14 marcelgmr static struct rover_t {
60 ada8fba9 2014-11-09 marcelgmr int tab;
61 71ee1627 2014-11-07 marcelgmr int nfiles;
62 ada8fba9 2014-11-09 marcelgmr int scroll[10];
63 7c74df90 2014-11-15 marcelgmr int esel[10];
64 47e9f26d 2014-11-09 marcelgmr uint8_t flags[10];
65 576e768d 2014-11-08 marcelgmr row_t *rows;
66 71ee1627 2014-11-07 marcelgmr WINDOW *window;
67 ada8fba9 2014-11-09 marcelgmr char cwd[10][FILENAME_MAX];
68 18016333 2014-11-14 marcelgmr marks_t marks;
69 f05efd9e 2014-11-07 marcelgmr } rover;
70 71ee1627 2014-11-07 marcelgmr
71 3cd6bb98 2014-11-11 marcelgmr /* Macros for accessing global state. */
72 7c74df90 2014-11-15 marcelgmr #define ENAME(I) rover.rows[I].name
73 7c74df90 2014-11-15 marcelgmr #define ESIZE(I) rover.rows[I].size
74 18016333 2014-11-14 marcelgmr #define MARKED(I) rover.rows[I].marked
75 3cd6bb98 2014-11-11 marcelgmr #define SCROLL rover.scroll[rover.tab]
76 7c74df90 2014-11-15 marcelgmr #define ESEL rover.esel[rover.tab]
77 3cd6bb98 2014-11-11 marcelgmr #define FLAGS rover.flags[rover.tab]
78 3cd6bb98 2014-11-11 marcelgmr #define CWD rover.cwd[rover.tab]
79 845f2b87 2014-11-14 marcelgmr
80 60128fcd 2014-11-15 marcelgmr /* Helpers. */
81 60128fcd 2014-11-15 marcelgmr #define MIN(A, B) ((A) < (B) ? (A) : (B))
82 60128fcd 2014-11-15 marcelgmr #define MAX(A, B) ((A) > (B) ? (A) : (B))
83 7c74df90 2014-11-15 marcelgmr #define ISDIR(E) (strchr((E), '/') != NULL)
84 7c74df90 2014-11-15 marcelgmr
85 60128fcd 2014-11-15 marcelgmr typedef enum {DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, MAGENTA, WHITE} color_t;
86 845f2b87 2014-11-14 marcelgmr typedef int (*PROCESS)(const char *path);
87 576e768d 2014-11-08 marcelgmr
88 d06e977d 2014-11-14 marcelgmr static void
89 18016333 2014-11-14 marcelgmr init_marks(marks_t *marks)
90 18016333 2014-11-14 marcelgmr {
91 18016333 2014-11-14 marcelgmr strcpy(marks->dirpath, "");
92 18016333 2014-11-14 marcelgmr marks->bulk = BULK_INIT;
93 18016333 2014-11-14 marcelgmr marks->nentries = 0;
94 18016333 2014-11-14 marcelgmr marks->entries = (char **) calloc(marks->bulk, sizeof(char *));
95 18016333 2014-11-14 marcelgmr }
96 18016333 2014-11-14 marcelgmr
97 5c4a6b62 2014-11-14 marcelgmr /* Unmark all entries. */
98 d06e977d 2014-11-14 marcelgmr static void
99 18016333 2014-11-14 marcelgmr mark_none(marks_t *marks)
100 18016333 2014-11-14 marcelgmr {
101 18016333 2014-11-14 marcelgmr int i;
102 18016333 2014-11-14 marcelgmr
103 8ba07de5 2014-11-14 marcelgmr strcpy(marks->dirpath, "");
104 18016333 2014-11-14 marcelgmr for (i = 0; i < marks->bulk && marks->nentries; i++)
105 18016333 2014-11-14 marcelgmr if (marks->entries[i]) {
106 18016333 2014-11-14 marcelgmr free(marks->entries[i]);
107 9a852838 2014-11-14 marcelgmr marks->entries[i] = NULL;
108 18016333 2014-11-14 marcelgmr marks->nentries--;
109 18016333 2014-11-14 marcelgmr }
110 18016333 2014-11-14 marcelgmr if (marks->bulk > BULK_THRESH) {
111 18016333 2014-11-14 marcelgmr /* Reset bulk to free some memory. */
112 18016333 2014-11-14 marcelgmr free(marks->entries);
113 18016333 2014-11-14 marcelgmr marks->bulk = BULK_INIT;
114 18016333 2014-11-14 marcelgmr marks->entries = (char **) calloc(marks->bulk, sizeof(char *));
115 18016333 2014-11-14 marcelgmr }
116 18016333 2014-11-14 marcelgmr }
117 18016333 2014-11-14 marcelgmr
118 d06e977d 2014-11-14 marcelgmr static void
119 18016333 2014-11-14 marcelgmr add_mark(marks_t *marks, char *dirpath, char *entry)
120 18016333 2014-11-14 marcelgmr {
121 18016333 2014-11-14 marcelgmr int i;
122 18016333 2014-11-14 marcelgmr
123 18016333 2014-11-14 marcelgmr if (!strcmp(marks->dirpath, dirpath)) {
124 18016333 2014-11-14 marcelgmr /* Append mark to directory. */
125 18016333 2014-11-14 marcelgmr if (marks->nentries == marks->bulk) {
126 18016333 2014-11-14 marcelgmr /* Expand bulk to accomodate new entry. */
127 18016333 2014-11-14 marcelgmr int extra = marks->bulk >> 1;
128 18016333 2014-11-14 marcelgmr marks->bulk += extra; /* bulk *= 1.5; */
129 18016333 2014-11-14 marcelgmr marks->entries = (char **) realloc(
130 18016333 2014-11-14 marcelgmr marks->entries, marks->bulk * sizeof(char *)
131 18016333 2014-11-14 marcelgmr );
132 efd4828a 2014-11-14 marcelgmr memset(&marks->entries[marks->nentries], 0, extra * sizeof(char *));
133 18016333 2014-11-14 marcelgmr i = marks->nentries;
134 18016333 2014-11-14 marcelgmr }
135 18016333 2014-11-14 marcelgmr else {
136 18016333 2014-11-14 marcelgmr /* Search for empty slot (there must be one). */
137 18016333 2014-11-14 marcelgmr for (i = 0; i < marks->bulk; i++)
138 18016333 2014-11-14 marcelgmr if (!marks->entries[i])
139 18016333 2014-11-14 marcelgmr break;
140 18016333 2014-11-14 marcelgmr }
141 18016333 2014-11-14 marcelgmr }
142 18016333 2014-11-14 marcelgmr else {
143 18016333 2014-11-14 marcelgmr /* Directory changed. Discard old marks. */
144 18016333 2014-11-14 marcelgmr mark_none(marks);
145 18016333 2014-11-14 marcelgmr strcpy(marks->dirpath, dirpath);
146 18016333 2014-11-14 marcelgmr i = 0;
147 18016333 2014-11-14 marcelgmr }
148 18016333 2014-11-14 marcelgmr marks->entries[i] = (char *) malloc(strlen(entry) + 1);
149 18016333 2014-11-14 marcelgmr strcpy(marks->entries[i], entry);
150 18016333 2014-11-14 marcelgmr marks->nentries++;
151 18016333 2014-11-14 marcelgmr }
152 18016333 2014-11-14 marcelgmr
153 d06e977d 2014-11-14 marcelgmr static void
154 18016333 2014-11-14 marcelgmr del_mark(marks_t *marks, char *entry)
155 18016333 2014-11-14 marcelgmr {
156 18016333 2014-11-14 marcelgmr int i;
157 18016333 2014-11-14 marcelgmr
158 18016333 2014-11-14 marcelgmr if (marks->nentries > 1) {
159 18016333 2014-11-14 marcelgmr for (i = 0; i < marks->bulk; i++)
160 18016333 2014-11-14 marcelgmr if (marks->entries[i] && !strcmp(marks->entries[i], entry))
161 18016333 2014-11-14 marcelgmr break;
162 18016333 2014-11-14 marcelgmr free(marks->entries[i]);
163 18016333 2014-11-14 marcelgmr marks->entries[i] = NULL;
164 18016333 2014-11-14 marcelgmr marks->nentries--;
165 18016333 2014-11-14 marcelgmr }
166 18016333 2014-11-14 marcelgmr else mark_none(marks);
167 18016333 2014-11-14 marcelgmr }
168 18016333 2014-11-14 marcelgmr
169 d06e977d 2014-11-14 marcelgmr static void
170 c3758004 2014-11-15 marcelgmr free_marks(marks_t *marks)
171 18016333 2014-11-14 marcelgmr {
172 18016333 2014-11-14 marcelgmr int i;
173 18016333 2014-11-14 marcelgmr
174 18016333 2014-11-14 marcelgmr for (i = 0; i < marks->bulk && marks->nentries; i++)
175 18016333 2014-11-14 marcelgmr if (marks->entries[i]) {
176 18016333 2014-11-14 marcelgmr free(marks->entries[i]);
177 18016333 2014-11-14 marcelgmr marks->nentries--;
178 18016333 2014-11-14 marcelgmr }
179 18016333 2014-11-14 marcelgmr free(marks->entries);
180 18016333 2014-11-14 marcelgmr }
181 b25c9834 2014-11-14 marcelgmr
182 b25c9834 2014-11-14 marcelgmr static void message(const char *msg, color_t color);
183 18016333 2014-11-14 marcelgmr
184 f340950f 2014-11-11 marcelgmr static void handle_segv(int sig);
185 3cd6bb98 2014-11-11 marcelgmr static void handle_winch(int sig);
186 e1c42cfe 2014-11-11 marcelgmr
187 3cd6bb98 2014-11-11 marcelgmr /* Curses setup. */
188 71ee1627 2014-11-07 marcelgmr static void
189 f05efd9e 2014-11-07 marcelgmr init_term()
190 71ee1627 2014-11-07 marcelgmr {
191 e1c42cfe 2014-11-11 marcelgmr struct sigaction sa;
192 e1c42cfe 2014-11-11 marcelgmr
193 71ee1627 2014-11-07 marcelgmr setlocale(LC_ALL, "");
194 71ee1627 2014-11-07 marcelgmr initscr();
195 71ee1627 2014-11-07 marcelgmr cbreak(); /* Get one character at a time. */
196 71ee1627 2014-11-07 marcelgmr noecho();
197 71ee1627 2014-11-07 marcelgmr nonl(); /* No NL->CR/NL on output. */
198 71ee1627 2014-11-07 marcelgmr intrflush(stdscr, FALSE);
199 71ee1627 2014-11-07 marcelgmr keypad(stdscr, TRUE);
200 71ee1627 2014-11-07 marcelgmr curs_set(FALSE); /* Hide blinking cursor. */
201 e1c42cfe 2014-11-11 marcelgmr memset(&sa, 0, sizeof(struct sigaction));
202 f340950f 2014-11-11 marcelgmr /* Setup SIGSEGV handler. */
203 f340950f 2014-11-11 marcelgmr sa.sa_handler = handle_segv;
204 f340950f 2014-11-11 marcelgmr sigaction(SIGSEGV, &sa, NULL);
205 f340950f 2014-11-11 marcelgmr /* Setup SIGWINCH handler. */
206 e1c42cfe 2014-11-11 marcelgmr sa.sa_handler = handle_winch;
207 e1c42cfe 2014-11-11 marcelgmr sigaction(SIGWINCH, &sa, NULL);
208 71ee1627 2014-11-07 marcelgmr if (has_colors()) {
209 71ee1627 2014-11-07 marcelgmr start_color();
210 71ee1627 2014-11-07 marcelgmr init_pair(RED, COLOR_RED, COLOR_BLACK);
211 71ee1627 2014-11-07 marcelgmr init_pair(GREEN, COLOR_GREEN, COLOR_BLACK);
212 71ee1627 2014-11-07 marcelgmr init_pair(YELLOW, COLOR_YELLOW,COLOR_BLACK);
213 71ee1627 2014-11-07 marcelgmr init_pair(BLUE, COLOR_BLUE, COLOR_BLACK);
214 71ee1627 2014-11-07 marcelgmr init_pair(CYAN, COLOR_CYAN, COLOR_BLACK);
215 71ee1627 2014-11-07 marcelgmr init_pair(MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
216 71ee1627 2014-11-07 marcelgmr init_pair(WHITE, COLOR_WHITE, COLOR_BLACK);
217 71ee1627 2014-11-07 marcelgmr }
218 7c74df90 2014-11-15 marcelgmr atexit((void (*)(void)) endwin);
219 71ee1627 2014-11-07 marcelgmr }
220 71ee1627 2014-11-07 marcelgmr
221 3cd6bb98 2014-11-11 marcelgmr /* Update the listing view. */
222 71ee1627 2014-11-07 marcelgmr static void
223 743e70b8 2014-11-14 marcelgmr update_view()
224 71ee1627 2014-11-07 marcelgmr {
225 222db952 2014-11-08 marcelgmr int i, j;
226 576e768d 2014-11-08 marcelgmr int ishidden, isdir;
227 18016333 2014-11-14 marcelgmr int marking;
228 71ee1627 2014-11-07 marcelgmr
229 41aae0b0 2014-11-11 marcelgmr mvhline(0, 0, ' ', COLS);
230 41aae0b0 2014-11-11 marcelgmr color_set(RVC_CWD, NULL);
231 41aae0b0 2014-11-11 marcelgmr mvaddnstr(0, 0, CWD, COLS);
232 41aae0b0 2014-11-11 marcelgmr color_set(DEFAULT, NULL);
233 41aae0b0 2014-11-11 marcelgmr attr_on(A_BOLD, NULL);
234 41aae0b0 2014-11-11 marcelgmr color_set(RVC_TABNUM, NULL);
235 41aae0b0 2014-11-11 marcelgmr mvaddch(0, COLS-4, rover.tab + '0');
236 41aae0b0 2014-11-11 marcelgmr color_set(DEFAULT, NULL);
237 41aae0b0 2014-11-11 marcelgmr attr_off(A_BOLD, NULL);
238 41aae0b0 2014-11-11 marcelgmr wclear(rover.window);
239 41aae0b0 2014-11-11 marcelgmr wcolor_set(rover.window, RVC_BORDER, NULL);
240 41aae0b0 2014-11-11 marcelgmr wborder(rover.window, 0, 0, 0, 0, 0, 0, 0, 0);
241 41aae0b0 2014-11-11 marcelgmr wcolor_set(rover.window, DEFAULT, NULL);
242 667d4907 2014-11-14 marcelgmr /* Selection might not be visible, due to cursor wrapping or window
243 667d4907 2014-11-14 marcelgmr shrinking. In that case, the scroll must be moved to make it visible. */
244 60128fcd 2014-11-15 marcelgmr SCROLL = MAX(MIN(SCROLL, ESEL), ESEL - HEIGHT + 1);
245 18016333 2014-11-14 marcelgmr marking = !strcmp(CWD, rover.marks.dirpath);
246 ada8fba9 2014-11-09 marcelgmr for (i = 0, j = SCROLL; i < HEIGHT && j < rover.nfiles; i++, j++) {
247 7c74df90 2014-11-15 marcelgmr ishidden = ENAME(j)[0] == '.';
248 7c74df90 2014-11-15 marcelgmr isdir = ISDIR(ENAME(j));
249 7c74df90 2014-11-15 marcelgmr if (j == ESEL)
250 f05efd9e 2014-11-07 marcelgmr wattr_on(rover.window, A_REVERSE, NULL);
251 576e768d 2014-11-08 marcelgmr if (ishidden)
252 37233869 2014-11-07 marcelgmr wcolor_set(rover.window, RVC_HIDDEN, NULL);
253 576e768d 2014-11-08 marcelgmr else if (isdir)
254 37233869 2014-11-07 marcelgmr wcolor_set(rover.window, RVC_DIR, NULL);
255 37233869 2014-11-07 marcelgmr else
256 37233869 2014-11-07 marcelgmr wcolor_set(rover.window, RVC_FILE, NULL);
257 576e768d 2014-11-08 marcelgmr if (!isdir)
258 7c74df90 2014-11-15 marcelgmr sprintf(ROW, "%s%*d", ENAME(j),
259 7c74df90 2014-11-15 marcelgmr COLS - strlen(ENAME(j)) - 4, (int) ESIZE(j));
260 576e768d 2014-11-08 marcelgmr else
261 7c74df90 2014-11-15 marcelgmr strcpy(ROW, ENAME(j));
262 a81852bf 2014-11-08 marcelgmr mvwhline(rover.window, i + 1, 1, ' ', COLS - 2);
263 a651a76d 2014-11-14 marcelgmr if (marking && MARKED(j))
264 e6a7541a 2014-11-14 marcelgmr mvwaddch(rover.window, i + 1, 1, RVS_MARK);
265 18016333 2014-11-14 marcelgmr else
266 18016333 2014-11-14 marcelgmr mvwaddch(rover.window, i + 1, 1, ' ');
267 18016333 2014-11-14 marcelgmr mvwaddnstr(rover.window, i + 1, 3, ROW, COLS - 4);
268 37233869 2014-11-07 marcelgmr wcolor_set(rover.window, DEFAULT, NULL);
269 7c74df90 2014-11-15 marcelgmr if (j == ESEL)
270 f05efd9e 2014-11-07 marcelgmr wattr_off(rover.window, A_REVERSE, NULL);
271 a81852bf 2014-11-08 marcelgmr }
272 a81852bf 2014-11-08 marcelgmr if (rover.nfiles > HEIGHT) {
273 a81852bf 2014-11-08 marcelgmr int center, height;
274 ada8fba9 2014-11-09 marcelgmr center = (SCROLL + (HEIGHT >> 1)) * HEIGHT / rover.nfiles;
275 a81852bf 2014-11-08 marcelgmr height = (HEIGHT-1) * HEIGHT / rover.nfiles;
276 a81852bf 2014-11-08 marcelgmr if (!height) height = 1;
277 a81852bf 2014-11-08 marcelgmr wcolor_set(rover.window, RVC_BORDER, NULL);
278 a81852bf 2014-11-08 marcelgmr wborder(rover.window, 0, 0, 0, 0, 0, 0, 0, 0);
279 2a2b72b6 2014-11-08 marcelgmr wcolor_set(rover.window, RVC_SCROLLBAR, NULL);
280 4c8a3f34 2014-11-14 marcelgmr mvwvline(rover.window, center-(height>>1)+1, COLS-1, RVS_SCROLLBAR, height);
281 a81852bf 2014-11-08 marcelgmr wcolor_set(rover.window, DEFAULT, NULL);
282 71ee1627 2014-11-07 marcelgmr }
283 f05efd9e 2014-11-07 marcelgmr wrefresh(rover.window);
284 47e9f26d 2014-11-09 marcelgmr STATUS[0] = FLAGS & SHOW_FILES ? 'F' : ' ';
285 47e9f26d 2014-11-09 marcelgmr STATUS[1] = FLAGS & SHOW_DIRS ? 'D' : ' ';
286 47e9f26d 2014-11-09 marcelgmr STATUS[2] = FLAGS & SHOW_HIDDEN ? 'H' : ' ';
287 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles)
288 222db952 2014-11-08 marcelgmr strcpy(ROW, "0/0");
289 bb90b2d2 2014-11-08 marcelgmr else
290 7c74df90 2014-11-15 marcelgmr sprintf(ROW, "%d/%d", ESEL + 1, rover.nfiles);
291 7c74df90 2014-11-15 marcelgmr sprintf(STATUS+3, "%12s", ROW);
292 e1f31679 2014-11-07 marcelgmr color_set(RVC_STATUS, NULL);
293 50c63039 2014-11-14 marcelgmr mvaddstr(LINES - 1, STATUSPOS, STATUS);
294 e1f31679 2014-11-07 marcelgmr color_set(DEFAULT, NULL);
295 71ee1627 2014-11-07 marcelgmr refresh();
296 71ee1627 2014-11-07 marcelgmr }
297 71ee1627 2014-11-07 marcelgmr
298 41aae0b0 2014-11-11 marcelgmr /* SIGSEGV handler: clean up curses before exiting. */
299 41aae0b0 2014-11-11 marcelgmr static void
300 41aae0b0 2014-11-11 marcelgmr handle_segv(int sig)
301 41aae0b0 2014-11-11 marcelgmr {
302 41aae0b0 2014-11-11 marcelgmr (void) sig;
303 7c74df90 2014-11-15 marcelgmr endwin();
304 41aae0b0 2014-11-11 marcelgmr puts("Received SIGSEGV (segmentation fault).");
305 41aae0b0 2014-11-11 marcelgmr exit(1);
306 41aae0b0 2014-11-11 marcelgmr }
307 41aae0b0 2014-11-11 marcelgmr
308 41aae0b0 2014-11-11 marcelgmr /* SIGWINCH handler: resize application according to new terminal settings. */
309 41aae0b0 2014-11-11 marcelgmr static void
310 41aae0b0 2014-11-11 marcelgmr handle_winch(int sig)
311 41aae0b0 2014-11-11 marcelgmr {
312 41aae0b0 2014-11-11 marcelgmr (void) sig;
313 41aae0b0 2014-11-11 marcelgmr delwin(rover.window);
314 41aae0b0 2014-11-11 marcelgmr endwin();
315 41aae0b0 2014-11-11 marcelgmr refresh();
316 41aae0b0 2014-11-11 marcelgmr clear();
317 41aae0b0 2014-11-11 marcelgmr rover.window = subwin(stdscr, LINES - 2, COLS, 1, 0);
318 743e70b8 2014-11-14 marcelgmr update_view();
319 41aae0b0 2014-11-11 marcelgmr }
320 41aae0b0 2014-11-11 marcelgmr
321 3cd6bb98 2014-11-11 marcelgmr /* Comparison used to sort listing entries. */
322 3cd6bb98 2014-11-11 marcelgmr static int
323 3cd6bb98 2014-11-11 marcelgmr rowcmp(const void *a, const void *b)
324 3cd6bb98 2014-11-11 marcelgmr {
325 3cd6bb98 2014-11-11 marcelgmr int isdir1, isdir2, cmpdir;
326 3cd6bb98 2014-11-11 marcelgmr const row_t *r1 = a;
327 3cd6bb98 2014-11-11 marcelgmr const row_t *r2 = b;
328 7c74df90 2014-11-15 marcelgmr isdir1 = ISDIR(r1->name);
329 7c74df90 2014-11-15 marcelgmr isdir2 = ISDIR(r2->name);
330 3cd6bb98 2014-11-11 marcelgmr cmpdir = isdir2 - isdir1;
331 3cd6bb98 2014-11-11 marcelgmr return cmpdir ? cmpdir : strcoll(r1->name, r2->name);
332 3cd6bb98 2014-11-11 marcelgmr }
333 3cd6bb98 2014-11-11 marcelgmr
334 3cd6bb98 2014-11-11 marcelgmr /* Get all entries for a given path (usually cwd). */
335 3cd6bb98 2014-11-11 marcelgmr static int
336 3cd6bb98 2014-11-11 marcelgmr ls(char *path, row_t **rowsp, uint8_t flags)
337 3cd6bb98 2014-11-11 marcelgmr {
338 3cd6bb98 2014-11-11 marcelgmr DIR *dp;
339 3cd6bb98 2014-11-11 marcelgmr struct dirent *ep;
340 3cd6bb98 2014-11-11 marcelgmr struct stat statbuf;
341 3cd6bb98 2014-11-11 marcelgmr row_t *rows;
342 3cd6bb98 2014-11-11 marcelgmr int i, n;
343 3cd6bb98 2014-11-11 marcelgmr
344 7c74df90 2014-11-15 marcelgmr if(!(dp = opendir(path))) return -1;
345 3cd6bb98 2014-11-11 marcelgmr n = -2; /* We don't want the entries "." and "..". */
346 3cd6bb98 2014-11-11 marcelgmr while (readdir(dp)) n++;
347 3cd6bb98 2014-11-11 marcelgmr rewinddir(dp);
348 3cd6bb98 2014-11-11 marcelgmr rows = (row_t *) malloc(n * sizeof(row_t));
349 3cd6bb98 2014-11-11 marcelgmr i = 0;
350 3cd6bb98 2014-11-11 marcelgmr while ((ep = readdir(dp))) {
351 3cd6bb98 2014-11-11 marcelgmr if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
352 3cd6bb98 2014-11-11 marcelgmr continue;
353 3cd6bb98 2014-11-11 marcelgmr if (!(flags & SHOW_HIDDEN) && ep->d_name[0] == '.')
354 3cd6bb98 2014-11-11 marcelgmr continue;
355 3cd6bb98 2014-11-11 marcelgmr /* FIXME: ANSI C doesn't have lstat(). How do we handle symlinks? */
356 3cd6bb98 2014-11-11 marcelgmr stat(ep->d_name, &statbuf);
357 3cd6bb98 2014-11-11 marcelgmr if (S_ISDIR(statbuf.st_mode)) {
358 3cd6bb98 2014-11-11 marcelgmr if (flags & SHOW_DIRS) {
359 3cd6bb98 2014-11-11 marcelgmr rows[i].name = (char *) malloc(strlen(ep->d_name) + 2);
360 3cd6bb98 2014-11-11 marcelgmr strcpy(rows[i].name, ep->d_name);
361 3cd6bb98 2014-11-11 marcelgmr strcat(rows[i].name, "/");
362 3cd6bb98 2014-11-11 marcelgmr i++;
363 3cd6bb98 2014-11-11 marcelgmr }
364 3cd6bb98 2014-11-11 marcelgmr }
365 3cd6bb98 2014-11-11 marcelgmr else if (flags & SHOW_FILES) {
366 3cd6bb98 2014-11-11 marcelgmr rows[i].name = (char *) malloc(strlen(ep->d_name) + 1);
367 3cd6bb98 2014-11-11 marcelgmr strcpy(rows[i].name, ep->d_name);
368 3cd6bb98 2014-11-11 marcelgmr rows[i].size = statbuf.st_size;
369 3cd6bb98 2014-11-11 marcelgmr i++;
370 3cd6bb98 2014-11-11 marcelgmr }
371 3cd6bb98 2014-11-11 marcelgmr }
372 3cd6bb98 2014-11-11 marcelgmr n = i; /* Ignore unused space in array caused by filters. */
373 3cd6bb98 2014-11-11 marcelgmr qsort(rows, n, sizeof(row_t), rowcmp);
374 3cd6bb98 2014-11-11 marcelgmr closedir(dp);
375 3cd6bb98 2014-11-11 marcelgmr *rowsp = rows;
376 3cd6bb98 2014-11-11 marcelgmr return n;
377 3cd6bb98 2014-11-11 marcelgmr }
378 3cd6bb98 2014-11-11 marcelgmr
379 3cd6bb98 2014-11-11 marcelgmr static void
380 3cd6bb98 2014-11-11 marcelgmr free_rows(row_t **rowsp, int nfiles)
381 3cd6bb98 2014-11-11 marcelgmr {
382 3cd6bb98 2014-11-11 marcelgmr int i;
383 3cd6bb98 2014-11-11 marcelgmr
384 3cd6bb98 2014-11-11 marcelgmr for (i = 0; i < nfiles; i++)
385 3cd6bb98 2014-11-11 marcelgmr free((*rowsp)[i].name);
386 3cd6bb98 2014-11-11 marcelgmr free(*rowsp);
387 3cd6bb98 2014-11-11 marcelgmr *rowsp = NULL;
388 3cd6bb98 2014-11-11 marcelgmr }
389 3cd6bb98 2014-11-11 marcelgmr
390 3cd6bb98 2014-11-11 marcelgmr /* Change working directory. */
391 ada8fba9 2014-11-09 marcelgmr /* NOTE: The caller needs to write the new path to CWD
392 71ee1627 2014-11-07 marcelgmr * *before* calling this function. */
393 71ee1627 2014-11-07 marcelgmr static void
394 ada8fba9 2014-11-09 marcelgmr cd(int reset)
395 71ee1627 2014-11-07 marcelgmr {
396 18016333 2014-11-14 marcelgmr int i, j;
397 18016333 2014-11-14 marcelgmr
398 60128fcd 2014-11-15 marcelgmr if (reset) ESEL = SCROLL = 0;
399 ea0214c3 2014-11-09 marcelgmr chdir(CWD);
400 f05efd9e 2014-11-07 marcelgmr if (rover.nfiles)
401 576e768d 2014-11-08 marcelgmr free_rows(&rover.rows, rover.nfiles);
402 47e9f26d 2014-11-09 marcelgmr rover.nfiles = ls(CWD, &rover.rows, FLAGS);
403 18016333 2014-11-14 marcelgmr if (!strcmp(CWD, rover.marks.dirpath)) {
404 18016333 2014-11-14 marcelgmr for (i = 0; i < rover.nfiles; i++) {
405 18016333 2014-11-14 marcelgmr for (j = 0; j < rover.marks.bulk; j++)
406 18016333 2014-11-14 marcelgmr if (
407 18016333 2014-11-14 marcelgmr rover.marks.entries[j] &&
408 7c74df90 2014-11-15 marcelgmr !strcmp(rover.marks.entries[j], ENAME(i))
409 18016333 2014-11-14 marcelgmr )
410 18016333 2014-11-14 marcelgmr break;
411 18016333 2014-11-14 marcelgmr MARKED(i) = j < rover.marks.bulk;
412 18016333 2014-11-14 marcelgmr }
413 18016333 2014-11-14 marcelgmr }
414 60128fcd 2014-11-15 marcelgmr else for (i = 0; i < rover.nfiles; i++)
415 60128fcd 2014-11-15 marcelgmr MARKED(i) = 0;
416 743e70b8 2014-11-14 marcelgmr update_view();
417 548a3163 2014-11-14 marcelgmr }
418 548a3163 2014-11-14 marcelgmr
419 5c4a6b62 2014-11-14 marcelgmr /* Recursively process a source directory using CWD as destination root.
420 5c4a6b62 2014-11-14 marcelgmr * For each node (i.e. directory), do the following:
421 5c4a6b62 2014-11-14 marcelgmr * 1. call pre(destination);
422 5c4a6b62 2014-11-14 marcelgmr * 2. call proc() on every child leaf (i.e. files);
423 5c4a6b62 2014-11-14 marcelgmr * 3. recurse into every child node;
424 5c4a6b62 2014-11-14 marcelgmr * 4. call pos(source).
425 5c4a6b62 2014-11-14 marcelgmr * E.g. to move directory /src/ (and all its contents) inside /dst/:
426 5c4a6b62 2014-11-14 marcelgmr * strcpy(CWD, "/dst/");
427 5c4a6b62 2014-11-14 marcelgmr * process_dir(adddir, movfile, deldir, "/src/");
428 5c4a6b62 2014-11-14 marcelgmr */
429 548a3163 2014-11-14 marcelgmr static void
430 845f2b87 2014-11-14 marcelgmr process_dir(PROCESS pre, PROCESS proc, PROCESS pos, const char *path)
431 548a3163 2014-11-14 marcelgmr {
432 548a3163 2014-11-14 marcelgmr DIR *dp;
433 548a3163 2014-11-14 marcelgmr struct dirent *ep;
434 548a3163 2014-11-14 marcelgmr struct stat statbuf;
435 548a3163 2014-11-14 marcelgmr char subpath[FILENAME_MAX];
436 548a3163 2014-11-14 marcelgmr
437 68ff0591 2014-11-14 marcelgmr if (pre) {
438 68ff0591 2014-11-14 marcelgmr char dstpath[FILENAME_MAX];
439 68ff0591 2014-11-14 marcelgmr strcpy(dstpath, CWD);
440 68ff0591 2014-11-14 marcelgmr strcat(dstpath, path + strlen(rover.marks.dirpath));
441 68ff0591 2014-11-14 marcelgmr pre(dstpath);
442 68ff0591 2014-11-14 marcelgmr }
443 7c74df90 2014-11-15 marcelgmr if(!(dp = opendir(path))) return;
444 548a3163 2014-11-14 marcelgmr while ((ep = readdir(dp))) {
445 548a3163 2014-11-14 marcelgmr if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
446 548a3163 2014-11-14 marcelgmr continue;
447 548a3163 2014-11-14 marcelgmr sprintf(subpath, "%s%s", path, ep->d_name);
448 548a3163 2014-11-14 marcelgmr stat(subpath, &statbuf);
449 548a3163 2014-11-14 marcelgmr if (S_ISDIR(statbuf.st_mode)) {
450 548a3163 2014-11-14 marcelgmr strcat(subpath, "/");
451 845f2b87 2014-11-14 marcelgmr process_dir(pre, proc, pos, subpath);
452 548a3163 2014-11-14 marcelgmr }
453 b25c9834 2014-11-14 marcelgmr else proc(subpath);
454 548a3163 2014-11-14 marcelgmr }
455 548a3163 2014-11-14 marcelgmr closedir(dp);
456 845f2b87 2014-11-14 marcelgmr if (pos) pos(path);
457 548a3163 2014-11-14 marcelgmr }
458 548a3163 2014-11-14 marcelgmr
459 5c4a6b62 2014-11-14 marcelgmr /* Process all marked entries using CWD as destination root.
460 5c4a6b62 2014-11-14 marcelgmr * All marked entries that are directories will be recursively processed.
461 5c4a6b62 2014-11-14 marcelgmr * See process_dir() for details on the parameters.
462 5c4a6b62 2014-11-14 marcelgmr */
463 548a3163 2014-11-14 marcelgmr static void
464 845f2b87 2014-11-14 marcelgmr process_marked(PROCESS pre, PROCESS proc, PROCESS pos)
465 548a3163 2014-11-14 marcelgmr {
466 548a3163 2014-11-14 marcelgmr int i;
467 548a3163 2014-11-14 marcelgmr char path[FILENAME_MAX];
468 548a3163 2014-11-14 marcelgmr
469 548a3163 2014-11-14 marcelgmr for (i = 0; i < rover.marks.bulk; i++)
470 548a3163 2014-11-14 marcelgmr if (rover.marks.entries[i]) {
471 548a3163 2014-11-14 marcelgmr sprintf(path, "%s%s", rover.marks.dirpath, rover.marks.entries[i]);
472 7c74df90 2014-11-15 marcelgmr if (ISDIR(rover.marks.entries[i])) {
473 b25c9834 2014-11-14 marcelgmr if (!strncmp(path, CWD, strlen(path)))
474 b25c9834 2014-11-14 marcelgmr message("Cannot copy/move directory inside itself.", RED);
475 b25c9834 2014-11-14 marcelgmr else
476 b25c9834 2014-11-14 marcelgmr process_dir(pre, proc, pos, path);
477 b25c9834 2014-11-14 marcelgmr }
478 b25c9834 2014-11-14 marcelgmr else proc(path);
479 548a3163 2014-11-14 marcelgmr }
480 60128fcd 2014-11-15 marcelgmr mark_none(&rover.marks);
481 60128fcd 2014-11-15 marcelgmr cd(1);
482 3cd6bb98 2014-11-11 marcelgmr }
483 3cd6bb98 2014-11-11 marcelgmr
484 b7ee4ee2 2014-11-14 marcelgmr /* Wrappers for file operations. */
485 ca8ebdce 2014-11-14 marcelgmr static PROCESS delfile = unlink;
486 b7ee4ee2 2014-11-14 marcelgmr static PROCESS deldir = rmdir;
487 1447784d 2014-11-14 marcelgmr static int addfile(const char *path) {
488 1447784d 2014-11-14 marcelgmr /* Using creat(2) because mknod(2) doesn't seem to be portable. */
489 1447784d 2014-11-14 marcelgmr int ret;
490 1447784d 2014-11-14 marcelgmr
491 1447784d 2014-11-14 marcelgmr ret = creat(path, 0644);
492 1447784d 2014-11-14 marcelgmr if (ret < 0) return ret;
493 1447784d 2014-11-14 marcelgmr return close(ret);
494 1447784d 2014-11-14 marcelgmr }
495 ca8ebdce 2014-11-14 marcelgmr static int cpyfile(const char *srcpath) {
496 b7ee4ee2 2014-11-14 marcelgmr int src, dst, ret;
497 b7ee4ee2 2014-11-14 marcelgmr size_t size;
498 b7ee4ee2 2014-11-14 marcelgmr struct stat st;
499 b7ee4ee2 2014-11-14 marcelgmr char buf[BUFSIZ];
500 b7ee4ee2 2014-11-14 marcelgmr char dstpath[FILENAME_MAX];
501 b7ee4ee2 2014-11-14 marcelgmr
502 b7ee4ee2 2014-11-14 marcelgmr ret = src = open(srcpath, O_RDONLY);
503 b7ee4ee2 2014-11-14 marcelgmr if (ret < 0) return ret;
504 b7ee4ee2 2014-11-14 marcelgmr ret = fstat(src, &st);
505 b7ee4ee2 2014-11-14 marcelgmr if (ret < 0) return ret;
506 b7ee4ee2 2014-11-14 marcelgmr strcpy(dstpath, CWD);
507 b7ee4ee2 2014-11-14 marcelgmr strcat(dstpath, srcpath + strlen(rover.marks.dirpath));
508 b7ee4ee2 2014-11-14 marcelgmr ret = dst = creat(dstpath, st.st_mode);
509 b7ee4ee2 2014-11-14 marcelgmr if (ret < 0) return ret;
510 b7ee4ee2 2014-11-14 marcelgmr while ((size = read(src, buf, BUFSIZ)) > 0)
511 b7ee4ee2 2014-11-14 marcelgmr write(dst, buf, size);
512 b7ee4ee2 2014-11-14 marcelgmr close(src);
513 b7ee4ee2 2014-11-14 marcelgmr close(dst);
514 b7ee4ee2 2014-11-14 marcelgmr return 0;
515 b7ee4ee2 2014-11-14 marcelgmr }
516 b7ee4ee2 2014-11-14 marcelgmr static int adddir(const char *path) {
517 b7ee4ee2 2014-11-14 marcelgmr int ret;
518 b7ee4ee2 2014-11-14 marcelgmr struct stat st;
519 b7ee4ee2 2014-11-14 marcelgmr
520 b7ee4ee2 2014-11-14 marcelgmr ret = stat(CWD, &st);
521 b7ee4ee2 2014-11-14 marcelgmr if (ret < 0) return ret;
522 b7ee4ee2 2014-11-14 marcelgmr return mkdir(path, st.st_mode);
523 ca8ebdce 2014-11-14 marcelgmr }
524 0ea64589 2014-11-14 marcelgmr static int movfile(const char *srcpath) {
525 0ea64589 2014-11-14 marcelgmr char dstpath[FILENAME_MAX];
526 ca8ebdce 2014-11-14 marcelgmr
527 0ea64589 2014-11-14 marcelgmr strcpy(dstpath, CWD);
528 0ea64589 2014-11-14 marcelgmr strcat(dstpath, srcpath + strlen(rover.marks.dirpath));
529 0ea64589 2014-11-14 marcelgmr return rename(srcpath, dstpath);
530 b7ee4ee2 2014-11-14 marcelgmr }
531 b7ee4ee2 2014-11-14 marcelgmr
532 6c0f3741 2014-11-11 marcelgmr /* Do a fork-exec to external program (e.g. $EDITOR). */
533 3cd6bb98 2014-11-11 marcelgmr static void
534 71ee1627 2014-11-07 marcelgmr spawn()
535 71ee1627 2014-11-07 marcelgmr {
536 71ee1627 2014-11-07 marcelgmr pid_t pid;
537 71ee1627 2014-11-07 marcelgmr int status;
538 71ee1627 2014-11-07 marcelgmr
539 71ee1627 2014-11-07 marcelgmr pid = fork();
540 71ee1627 2014-11-07 marcelgmr if (pid > 0) {
541 71ee1627 2014-11-07 marcelgmr /* fork() succeeded. */
542 7c74df90 2014-11-15 marcelgmr endwin();
543 ea0214c3 2014-11-09 marcelgmr waitpid(pid, &status, 0);
544 f05efd9e 2014-11-07 marcelgmr init_term();
545 71ee1627 2014-11-07 marcelgmr doupdate();
546 71ee1627 2014-11-07 marcelgmr }
547 71ee1627 2014-11-07 marcelgmr else if (pid == 0) {
548 71ee1627 2014-11-07 marcelgmr /* Child process. */
549 3cd6bb98 2014-11-11 marcelgmr execvp(ARGS[0], ARGS);
550 411ec846 2014-11-08 marcelgmr }
551 411ec846 2014-11-08 marcelgmr }
552 411ec846 2014-11-08 marcelgmr
553 411ec846 2014-11-08 marcelgmr /* Interactive getstr(). */
554 3cd6bb98 2014-11-11 marcelgmr static int
555 411ec846 2014-11-08 marcelgmr igetstr(char *buffer, int maxlen)
556 411ec846 2014-11-08 marcelgmr {
557 411ec846 2014-11-08 marcelgmr int ch, length;
558 411ec846 2014-11-08 marcelgmr
559 411ec846 2014-11-08 marcelgmr length = strlen(buffer);
560 d5fe31b0 2014-11-14 marcelgmr curs_set(TRUE);
561 411ec846 2014-11-08 marcelgmr ch = getch();
562 d5fe31b0 2014-11-14 marcelgmr if (ch == '\r' || ch == '\n' || ch == KEY_DOWN || ch == KEY_ENTER) {
563 d5fe31b0 2014-11-14 marcelgmr curs_set(FALSE);
564 411ec846 2014-11-08 marcelgmr return 0;
565 d5fe31b0 2014-11-14 marcelgmr }
566 411ec846 2014-11-08 marcelgmr else if (ch == erasechar() || ch == KEY_LEFT || ch == KEY_BACKSPACE) {
567 411ec846 2014-11-08 marcelgmr if (length)
568 411ec846 2014-11-08 marcelgmr buffer[--length] = '\0';
569 411ec846 2014-11-08 marcelgmr }
570 411ec846 2014-11-08 marcelgmr else if (ch == killchar()) {
571 411ec846 2014-11-08 marcelgmr length = 0;
572 411ec846 2014-11-08 marcelgmr buffer[0] = '\0';
573 71ee1627 2014-11-07 marcelgmr }
574 411ec846 2014-11-08 marcelgmr else if (length < maxlen - 1 && isprint(ch)) {
575 411ec846 2014-11-08 marcelgmr buffer[length++] = ch;
576 411ec846 2014-11-08 marcelgmr buffer[length] = '\0';
577 411ec846 2014-11-08 marcelgmr }
578 411ec846 2014-11-08 marcelgmr return 1;
579 743e70b8 2014-11-14 marcelgmr }
580 743e70b8 2014-11-14 marcelgmr
581 5c4a6b62 2014-11-14 marcelgmr /* Update line input on the screen. */
582 743e70b8 2014-11-14 marcelgmr static void
583 743e70b8 2014-11-14 marcelgmr update_input(char *prompt, color_t color)
584 743e70b8 2014-11-14 marcelgmr {
585 743e70b8 2014-11-14 marcelgmr int plen, ilen;
586 743e70b8 2014-11-14 marcelgmr
587 743e70b8 2014-11-14 marcelgmr plen = strlen(prompt);
588 743e70b8 2014-11-14 marcelgmr ilen = strlen(INPUT);
589 743e70b8 2014-11-14 marcelgmr color_set(RVC_PROMPT, NULL);
590 743e70b8 2014-11-14 marcelgmr mvaddstr(LINES - 1, 0, prompt);
591 743e70b8 2014-11-14 marcelgmr color_set(color, NULL);
592 743e70b8 2014-11-14 marcelgmr mvaddstr(LINES - 1, plen, INPUT);
593 743e70b8 2014-11-14 marcelgmr mvaddch(LINES - 1, ilen + plen, ' ');
594 743e70b8 2014-11-14 marcelgmr move(LINES - 1, ilen + plen);
595 743e70b8 2014-11-14 marcelgmr color_set(DEFAULT, NULL);
596 e1c42cfe 2014-11-11 marcelgmr }
597 e1c42cfe 2014-11-11 marcelgmr
598 a31a7b29 2014-11-15 marcelgmr /* Show a message on the status bar. */
599 50c63039 2014-11-14 marcelgmr static void
600 50c63039 2014-11-14 marcelgmr message(const char *msg, color_t color)
601 50c63039 2014-11-14 marcelgmr {
602 50c63039 2014-11-14 marcelgmr int len, pos;
603 50c63039 2014-11-14 marcelgmr
604 50c63039 2014-11-14 marcelgmr len = strlen(msg);
605 50c63039 2014-11-14 marcelgmr pos = (STATUSPOS - len) >> 1;
606 50c63039 2014-11-14 marcelgmr attr_on(A_BOLD, NULL);
607 50c63039 2014-11-14 marcelgmr color_set(color, NULL);
608 50c63039 2014-11-14 marcelgmr mvaddstr(LINES - 1, pos, msg);
609 50c63039 2014-11-14 marcelgmr color_set(DEFAULT, NULL);
610 50c63039 2014-11-14 marcelgmr attr_off(A_BOLD, NULL);
611 50c63039 2014-11-14 marcelgmr }
612 50c63039 2014-11-14 marcelgmr
613 71ee1627 2014-11-07 marcelgmr int
614 38a357b6 2014-11-09 marcelgmr main(int argc, char *argv[])
615 71ee1627 2014-11-07 marcelgmr {
616 ada8fba9 2014-11-09 marcelgmr int i, ch;
617 ada8fba9 2014-11-09 marcelgmr char *program, *key;
618 38a357b6 2014-11-09 marcelgmr DIR *d;
619 71ee1627 2014-11-07 marcelgmr
620 f05efd9e 2014-11-07 marcelgmr init_term();
621 f05efd9e 2014-11-07 marcelgmr rover.nfiles = 0;
622 47e9f26d 2014-11-09 marcelgmr for (i = 0; i < 10; i++) {
623 7c74df90 2014-11-15 marcelgmr rover.esel[i] = rover.scroll[i] = 0;
624 47e9f26d 2014-11-09 marcelgmr rover.flags[i] = SHOW_FILES | SHOW_DIRS;
625 47e9f26d 2014-11-09 marcelgmr }
626 ada8fba9 2014-11-09 marcelgmr strcpy(rover.cwd[0], getenv("HOME"));
627 38a357b6 2014-11-09 marcelgmr for (i = 1; i < argc && i < 10; i++) {
628 7c74df90 2014-11-15 marcelgmr if ((d = opendir(argv[i]))) {
629 38a357b6 2014-11-09 marcelgmr strcpy(rover.cwd[i], argv[i]);
630 38a357b6 2014-11-09 marcelgmr closedir(d);
631 38a357b6 2014-11-09 marcelgmr }
632 38a357b6 2014-11-09 marcelgmr else strcpy(rover.cwd[i], rover.cwd[0]);
633 38a357b6 2014-11-09 marcelgmr }
634 38a357b6 2014-11-09 marcelgmr getcwd(rover.cwd[i], FILENAME_MAX);
635 38a357b6 2014-11-09 marcelgmr for (i++; i < 10; i++)
636 38a357b6 2014-11-09 marcelgmr strcpy(rover.cwd[i], rover.cwd[i-1]);
637 38a357b6 2014-11-09 marcelgmr for (i = 0; i < 10; i++)
638 38a357b6 2014-11-09 marcelgmr if (rover.cwd[i][strlen(rover.cwd[i]) - 1] != '/')
639 38a357b6 2014-11-09 marcelgmr strcat(rover.cwd[i], "/");
640 ada8fba9 2014-11-09 marcelgmr rover.tab = 1;
641 ada8fba9 2014-11-09 marcelgmr rover.window = subwin(stdscr, LINES - 2, COLS, 1, 0);
642 18016333 2014-11-14 marcelgmr init_marks(&rover.marks);
643 ada8fba9 2014-11-09 marcelgmr cd(1);
644 0b301167 2014-11-07 marcelgmr while (1) {
645 ada8fba9 2014-11-09 marcelgmr ch = getch();
646 ada8fba9 2014-11-09 marcelgmr key = keyname(ch);
647 a31a7b29 2014-11-15 marcelgmr mvhline(LINES - 1, 0, ' ', STATUSPOS); /* Clear message area. */
648 a31a7b29 2014-11-15 marcelgmr if (!strcmp(key, RVK_QUIT)) break;
649 ada8fba9 2014-11-09 marcelgmr else if (ch >= '0' && ch <= '9') {
650 ada8fba9 2014-11-09 marcelgmr rover.tab = ch - '0';
651 ada8fba9 2014-11-09 marcelgmr cd(0);
652 ada8fba9 2014-11-09 marcelgmr }
653 0b301167 2014-11-07 marcelgmr else if (!strcmp(key, RVK_DOWN)) {
654 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles) continue;
655 7c74df90 2014-11-15 marcelgmr ESEL = (ESEL + 1) % rover.nfiles;
656 743e70b8 2014-11-14 marcelgmr update_view();
657 0b301167 2014-11-07 marcelgmr }
658 0b301167 2014-11-07 marcelgmr else if (!strcmp(key, RVK_UP)) {
659 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles) continue;
660 7c74df90 2014-11-15 marcelgmr ESEL = ESEL ? ESEL - 1 : rover.nfiles - 1;
661 743e70b8 2014-11-14 marcelgmr update_view();
662 0b301167 2014-11-07 marcelgmr }
663 0b301167 2014-11-07 marcelgmr else if (!strcmp(key, RVK_JUMP_DOWN)) {
664 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles) continue;
665 60128fcd 2014-11-15 marcelgmr ESEL = MIN(ESEL + RV_JUMP, rover.nfiles - 1);
666 60128fcd 2014-11-15 marcelgmr if (rover.nfiles > HEIGHT)
667 60128fcd 2014-11-15 marcelgmr SCROLL = MIN(SCROLL + RV_JUMP, rover.nfiles - HEIGHT);
668 743e70b8 2014-11-14 marcelgmr update_view();
669 0b301167 2014-11-07 marcelgmr }
670 0b301167 2014-11-07 marcelgmr else if (!strcmp(key, RVK_JUMP_UP)) {
671 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles) continue;
672 60128fcd 2014-11-15 marcelgmr ESEL = MAX(ESEL - RV_JUMP, 0);
673 60128fcd 2014-11-15 marcelgmr SCROLL = MAX(SCROLL - RV_JUMP, 0);
674 743e70b8 2014-11-14 marcelgmr update_view();
675 0b301167 2014-11-07 marcelgmr }
676 0b301167 2014-11-07 marcelgmr else if (!strcmp(key, RVK_CD_DOWN)) {
677 7c74df90 2014-11-15 marcelgmr if (!rover.nfiles || !ISDIR(ENAME(ESEL))) continue;
678 7c74df90 2014-11-15 marcelgmr strcat(CWD, ENAME(ESEL));
679 ada8fba9 2014-11-09 marcelgmr cd(1);
680 0b301167 2014-11-07 marcelgmr }
681 0b301167 2014-11-07 marcelgmr else if (!strcmp(key, RVK_CD_UP)) {
682 45020106 2014-11-08 marcelgmr char *dirname, first;
683 60128fcd 2014-11-15 marcelgmr if (strlen(CWD) == 1) continue;
684 ada8fba9 2014-11-09 marcelgmr CWD[strlen(CWD) - 1] = '\0';
685 ada8fba9 2014-11-09 marcelgmr dirname = strrchr(CWD, '/') + 1;
686 45020106 2014-11-08 marcelgmr first = dirname[0];
687 45020106 2014-11-08 marcelgmr dirname[0] = '\0';
688 ada8fba9 2014-11-09 marcelgmr cd(1);
689 47e9f26d 2014-11-09 marcelgmr if ((FLAGS & SHOW_DIRS) &&
690 47e9f26d 2014-11-09 marcelgmr ((FLAGS & SHOW_HIDDEN) || (first != '.'))
691 45020106 2014-11-08 marcelgmr ) {
692 45020106 2014-11-08 marcelgmr dirname[0] = first;
693 45020106 2014-11-08 marcelgmr dirname[strlen(dirname)] = '/';
694 7c74df90 2014-11-15 marcelgmr while (strcmp(ENAME(ESEL), dirname))
695 7c74df90 2014-11-15 marcelgmr ESEL++;
696 45020106 2014-11-08 marcelgmr if (rover.nfiles > HEIGHT) {
697 7c74df90 2014-11-15 marcelgmr SCROLL = ESEL - (HEIGHT >> 1);
698 60128fcd 2014-11-15 marcelgmr SCROLL = MIN(MAX(SCROLL, 0), rover.nfiles - HEIGHT);
699 45020106 2014-11-08 marcelgmr }
700 45020106 2014-11-08 marcelgmr dirname[0] = '\0';
701 743e70b8 2014-11-14 marcelgmr update_view();
702 45020106 2014-11-08 marcelgmr }
703 0b301167 2014-11-07 marcelgmr }
704 0b301167 2014-11-07 marcelgmr else if (!strcmp(key, RVK_HOME)) {
705 ada8fba9 2014-11-09 marcelgmr strcpy(CWD, getenv("HOME"));
706 ada8fba9 2014-11-09 marcelgmr if (CWD[strlen(CWD) - 1] != '/')
707 ada8fba9 2014-11-09 marcelgmr strcat(CWD, "/");
708 ada8fba9 2014-11-09 marcelgmr cd(1);
709 0b301167 2014-11-07 marcelgmr }
710 0b301167 2014-11-07 marcelgmr else if (!strcmp(key, RVK_SHELL)) {
711 71ee1627 2014-11-07 marcelgmr program = getenv("SHELL");
712 71ee1627 2014-11-07 marcelgmr if (program) {
713 3cd6bb98 2014-11-11 marcelgmr ARGS[0] = program;
714 3cd6bb98 2014-11-11 marcelgmr ARGS[1] = NULL;
715 71ee1627 2014-11-07 marcelgmr spawn();
716 39ee8f33 2014-11-14 marcelgmr cd(1);
717 71ee1627 2014-11-07 marcelgmr }
718 0b301167 2014-11-07 marcelgmr }
719 4b66a2c4 2014-11-07 marcelgmr else if (!strcmp(key, RVK_VIEW)) {
720 7c74df90 2014-11-15 marcelgmr if (!rover.nfiles || ISDIR(ENAME(ESEL))) continue;
721 4b66a2c4 2014-11-07 marcelgmr program = getenv("PAGER");
722 4b66a2c4 2014-11-07 marcelgmr if (program) {
723 3cd6bb98 2014-11-11 marcelgmr ARGS[0] = program;
724 7c74df90 2014-11-15 marcelgmr ARGS[1] = ENAME(ESEL);
725 3cd6bb98 2014-11-11 marcelgmr ARGS[2] = NULL;
726 4b66a2c4 2014-11-07 marcelgmr spawn();
727 4b66a2c4 2014-11-07 marcelgmr }
728 4b66a2c4 2014-11-07 marcelgmr }
729 0b301167 2014-11-07 marcelgmr else if (!strcmp(key, RVK_EDIT)) {
730 7c74df90 2014-11-15 marcelgmr if (!rover.nfiles || ISDIR(ENAME(ESEL))) continue;
731 71ee1627 2014-11-07 marcelgmr program = getenv("EDITOR");
732 71ee1627 2014-11-07 marcelgmr if (program) {
733 3cd6bb98 2014-11-11 marcelgmr ARGS[0] = program;
734 7c74df90 2014-11-15 marcelgmr ARGS[1] = ENAME(ESEL);
735 3cd6bb98 2014-11-11 marcelgmr ARGS[2] = NULL;
736 71ee1627 2014-11-07 marcelgmr spawn();
737 39ee8f33 2014-11-14 marcelgmr cd(0);
738 71ee1627 2014-11-07 marcelgmr }
739 0b301167 2014-11-07 marcelgmr }
740 a17e36e3 2014-11-07 marcelgmr else if (!strcmp(key, RVK_SEARCH)) {
741 1447784d 2014-11-14 marcelgmr int oldsel, oldscroll, length;
742 743e70b8 2014-11-14 marcelgmr char *prompt = "search: ";
743 bb90b2d2 2014-11-08 marcelgmr if (!rover.nfiles) continue;
744 7c74df90 2014-11-15 marcelgmr oldsel = ESEL;
745 ada8fba9 2014-11-09 marcelgmr oldscroll = SCROLL;
746 1447784d 2014-11-14 marcelgmr strcpy(INPUT, "");
747 743e70b8 2014-11-14 marcelgmr update_input(prompt, DEFAULT);
748 1447784d 2014-11-14 marcelgmr while (igetstr(INPUT, INPUTSZ)) {
749 1447784d 2014-11-14 marcelgmr int sel;
750 743e70b8 2014-11-14 marcelgmr color_t color = RED;
751 1447784d 2014-11-14 marcelgmr length = strlen(INPUT);
752 a17e36e3 2014-11-07 marcelgmr if (length) {
753 f05efd9e 2014-11-07 marcelgmr for (sel = 0; sel < rover.nfiles; sel++)
754 7c74df90 2014-11-15 marcelgmr if (!strncmp(ENAME(sel), INPUT, length))
755 a17e36e3 2014-11-07 marcelgmr break;
756 f05efd9e 2014-11-07 marcelgmr if (sel < rover.nfiles) {
757 a17e36e3 2014-11-07 marcelgmr color = GREEN;
758 7c74df90 2014-11-15 marcelgmr ESEL = sel;
759 f05efd9e 2014-11-07 marcelgmr if (rover.nfiles > HEIGHT) {
760 89cfd83b 2014-11-08 marcelgmr if (sel < 3)
761 ada8fba9 2014-11-09 marcelgmr SCROLL = 0;
762 89cfd83b 2014-11-08 marcelgmr else if (sel - 3 > rover.nfiles - HEIGHT)
763 ada8fba9 2014-11-09 marcelgmr SCROLL = rover.nfiles - HEIGHT;
764 a17e36e3 2014-11-07 marcelgmr else
765 ada8fba9 2014-11-09 marcelgmr SCROLL = sel - 3;
766 a17e36e3 2014-11-07 marcelgmr }
767 a17e36e3 2014-11-07 marcelgmr }
768 a17e36e3 2014-11-07 marcelgmr }
769 411ec846 2014-11-08 marcelgmr else {
770 7c74df90 2014-11-15 marcelgmr ESEL = oldsel;
771 ada8fba9 2014-11-09 marcelgmr SCROLL = oldscroll;
772 411ec846 2014-11-08 marcelgmr }
773 743e70b8 2014-11-14 marcelgmr update_view();
774 743e70b8 2014-11-14 marcelgmr update_input(prompt, color);
775 a17e36e3 2014-11-07 marcelgmr }
776 743e70b8 2014-11-14 marcelgmr mvhline(LINES - 1, 0, ' ', STATUSPOS);
777 743e70b8 2014-11-14 marcelgmr update_view();
778 a17e36e3 2014-11-07 marcelgmr }
779 bae1431c 2014-11-07 marcelgmr else if (!strcmp(key, RVK_TG_FILES)) {
780 47e9f26d 2014-11-09 marcelgmr FLAGS ^= SHOW_FILES;
781 ada8fba9 2014-11-09 marcelgmr cd(1);
782 bae1431c 2014-11-07 marcelgmr }
783 bae1431c 2014-11-07 marcelgmr else if (!strcmp(key, RVK_TG_DIRS)) {
784 47e9f26d 2014-11-09 marcelgmr FLAGS ^= SHOW_DIRS;
785 ada8fba9 2014-11-09 marcelgmr cd(1);
786 bae1431c 2014-11-07 marcelgmr }
787 bae1431c 2014-11-07 marcelgmr else if (!strcmp(key, RVK_TG_HIDDEN)) {
788 47e9f26d 2014-11-09 marcelgmr FLAGS ^= SHOW_HIDDEN;
789 ada8fba9 2014-11-09 marcelgmr cd(1);
790 bae1431c 2014-11-07 marcelgmr }
791 1447784d 2014-11-14 marcelgmr else if (!strcmp(key, RVK_NEW_FILE)) {
792 743e70b8 2014-11-14 marcelgmr int ok = 0;
793 743e70b8 2014-11-14 marcelgmr char *prompt = "new file: ";
794 1447784d 2014-11-14 marcelgmr strcpy(INPUT, "");
795 743e70b8 2014-11-14 marcelgmr update_input(prompt, DEFAULT);
796 1447784d 2014-11-14 marcelgmr while (igetstr(INPUT, INPUTSZ)) {
797 ddbe9d62 2014-11-14 marcelgmr int length = strlen(INPUT);
798 1447784d 2014-11-14 marcelgmr ok = 1;
799 e444d3b1 2014-11-14 marcelgmr for (i = 0; i < rover.nfiles; i++) {
800 ddbe9d62 2014-11-14 marcelgmr if (
801 7c74df90 2014-11-15 marcelgmr !strncmp(ENAME(i), INPUT, length) &&
802 7c74df90 2014-11-15 marcelgmr (!strcmp(ENAME(i) + length, "") ||
803 7c74df90 2014-11-15 marcelgmr !strcmp(ENAME(i) + length, "/"))
804 ddbe9d62 2014-11-14 marcelgmr ) {
805 1447784d 2014-11-14 marcelgmr ok = 0;
806 1447784d 2014-11-14 marcelgmr break;
807 1447784d 2014-11-14 marcelgmr }
808 e444d3b1 2014-11-14 marcelgmr }
809 743e70b8 2014-11-14 marcelgmr update_input(prompt, ok ? GREEN : RED);
810 1447784d 2014-11-14 marcelgmr }
811 743e70b8 2014-11-14 marcelgmr mvhline(LINES - 1, 0, ' ', STATUSPOS);
812 743e70b8 2014-11-14 marcelgmr if (strlen(INPUT)) {
813 532092a8 2014-11-14 marcelgmr if (ok) { addfile(INPUT); cd(1); }
814 1447784d 2014-11-14 marcelgmr else message("File already exists.", RED);
815 1447784d 2014-11-14 marcelgmr }
816 1447784d 2014-11-14 marcelgmr }
817 1447784d 2014-11-14 marcelgmr else if (!strcmp(key, RVK_NEW_DIR)) {
818 743e70b8 2014-11-14 marcelgmr int ok = 0;
819 743e70b8 2014-11-14 marcelgmr char *prompt = "new directory: ";
820 1447784d 2014-11-14 marcelgmr strcpy(INPUT, "");
821 743e70b8 2014-11-14 marcelgmr update_input(prompt, DEFAULT);
822 1447784d 2014-11-14 marcelgmr while (igetstr(INPUT, INPUTSZ)) {
823 ddbe9d62 2014-11-14 marcelgmr int length = strlen(INPUT);
824 1447784d 2014-11-14 marcelgmr ok = 1;
825 e444d3b1 2014-11-14 marcelgmr for (i = 0; i < rover.nfiles; i++) {
826 ddbe9d62 2014-11-14 marcelgmr if (
827 7c74df90 2014-11-15 marcelgmr !strncmp(ENAME(i), INPUT, length) &&
828 7c74df90 2014-11-15 marcelgmr (!strcmp(ENAME(i) + length, "") ||
829 7c74df90 2014-11-15 marcelgmr !strcmp(ENAME(i) + length, "/"))
830 ddbe9d62 2014-11-14 marcelgmr ) {
831 1447784d 2014-11-14 marcelgmr ok = 0;
832 1447784d 2014-11-14 marcelgmr break;
833 1447784d 2014-11-14 marcelgmr }
834 e444d3b1 2014-11-14 marcelgmr }
835 743e70b8 2014-11-14 marcelgmr update_input(prompt, ok ? GREEN : RED);
836 1447784d 2014-11-14 marcelgmr }
837 743e70b8 2014-11-14 marcelgmr mvhline(LINES - 1, 0, ' ', STATUSPOS);
838 743e70b8 2014-11-14 marcelgmr if (strlen(INPUT)) {
839 532092a8 2014-11-14 marcelgmr if (ok) { adddir(INPUT); cd(1); }
840 1447784d 2014-11-14 marcelgmr else message("File already exists.", RED);
841 1447784d 2014-11-14 marcelgmr }
842 1447784d 2014-11-14 marcelgmr }
843 bdb195d0 2014-11-14 marcelgmr else if (!strcmp(key, RVK_RENAME)) {
844 bdb195d0 2014-11-14 marcelgmr int ok = 0;
845 bdb195d0 2014-11-14 marcelgmr char *prompt = "rename: ";
846 7c74df90 2014-11-15 marcelgmr strcpy(INPUT, ENAME(ESEL));
847 ddbe9d62 2014-11-14 marcelgmr update_input(prompt, RED);
848 bdb195d0 2014-11-14 marcelgmr while (igetstr(INPUT, INPUTSZ)) {
849 ddbe9d62 2014-11-14 marcelgmr int length = strlen(INPUT);
850 bdb195d0 2014-11-14 marcelgmr ok = 1;
851 e444d3b1 2014-11-14 marcelgmr for (i = 0; i < rover.nfiles; i++) {
852 ddbe9d62 2014-11-14 marcelgmr if (
853 7c74df90 2014-11-15 marcelgmr !strncmp(ENAME(i), INPUT, length) &&
854 7c74df90 2014-11-15 marcelgmr (!strcmp(ENAME(i) + length, "") ||
855 7c74df90 2014-11-15 marcelgmr !strcmp(ENAME(i) + length, "/"))
856 ddbe9d62 2014-11-14 marcelgmr ) {
857 bdb195d0 2014-11-14 marcelgmr ok = 0;
858 bdb195d0 2014-11-14 marcelgmr break;
859 bdb195d0 2014-11-14 marcelgmr }
860 e444d3b1 2014-11-14 marcelgmr }
861 bdb195d0 2014-11-14 marcelgmr update_input(prompt, ok ? GREEN : RED);
862 bdb195d0 2014-11-14 marcelgmr }
863 bdb195d0 2014-11-14 marcelgmr mvhline(LINES - 1, 0, ' ', STATUSPOS);
864 bdb195d0 2014-11-14 marcelgmr if (strlen(INPUT)) {
865 7c74df90 2014-11-15 marcelgmr if (ok) { rename(ENAME(ESEL), INPUT); cd(1); }
866 bdb195d0 2014-11-14 marcelgmr else message("File already exists.", RED);
867 bdb195d0 2014-11-14 marcelgmr }
868 bdb195d0 2014-11-14 marcelgmr }
869 18016333 2014-11-14 marcelgmr else if (!strcmp(key, RVK_TG_MARK)) {
870 7c74df90 2014-11-15 marcelgmr if (MARKED(ESEL))
871 7c74df90 2014-11-15 marcelgmr del_mark(&rover.marks, ENAME(ESEL));
872 18016333 2014-11-14 marcelgmr else
873 7c74df90 2014-11-15 marcelgmr add_mark(&rover.marks, CWD, ENAME(ESEL));
874 7c74df90 2014-11-15 marcelgmr MARKED(ESEL) = !MARKED(ESEL);
875 7c74df90 2014-11-15 marcelgmr ESEL = (ESEL + 1) % rover.nfiles;
876 743e70b8 2014-11-14 marcelgmr update_view();
877 18016333 2014-11-14 marcelgmr }
878 18016333 2014-11-14 marcelgmr else if (!strcmp(key, RVK_INVMARK)) {
879 5fc8b927 2014-11-14 marcelgmr for (i = 0; i < rover.nfiles; i++) {
880 5fc8b927 2014-11-14 marcelgmr if (MARKED(i))
881 7c74df90 2014-11-15 marcelgmr del_mark(&rover.marks, ENAME(i));
882 5fc8b927 2014-11-14 marcelgmr else
883 7c74df90 2014-11-15 marcelgmr add_mark(&rover.marks, CWD, ENAME(i));
884 5fc8b927 2014-11-14 marcelgmr MARKED(i) = !MARKED(i);
885 5fc8b927 2014-11-14 marcelgmr }
886 743e70b8 2014-11-14 marcelgmr update_view();
887 18016333 2014-11-14 marcelgmr }
888 5fc8b927 2014-11-14 marcelgmr else if (!strcmp(key, RVK_MARKALL)) {
889 5fc8b927 2014-11-14 marcelgmr for (i = 0; i < rover.nfiles; i++)
890 5fc8b927 2014-11-14 marcelgmr if (!MARKED(i)) {
891 7c74df90 2014-11-15 marcelgmr add_mark(&rover.marks, CWD, ENAME(i));
892 5fc8b927 2014-11-14 marcelgmr MARKED(i) = 1;
893 5fc8b927 2014-11-14 marcelgmr }
894 743e70b8 2014-11-14 marcelgmr update_view();
895 548a3163 2014-11-14 marcelgmr }
896 a31a7b29 2014-11-15 marcelgmr else if (!strcmp(key, RVK_DELETE)) {
897 a31a7b29 2014-11-15 marcelgmr if (rover.marks.nentries) {
898 a31a7b29 2014-11-15 marcelgmr message("Delete marked entries? (Y to confirm)", YELLOW);
899 a31a7b29 2014-11-15 marcelgmr if (getch() == 'Y')
900 a31a7b29 2014-11-15 marcelgmr process_marked(NULL, delfile, deldir);
901 a31a7b29 2014-11-15 marcelgmr mvhline(LINES - 1, 0, ' ', STATUSPOS); /* Clear message area. */
902 a31a7b29 2014-11-15 marcelgmr }
903 a31a7b29 2014-11-15 marcelgmr else message("No entries marked for deletion.", RED);
904 a31a7b29 2014-11-15 marcelgmr }
905 a31a7b29 2014-11-15 marcelgmr else if (!strcmp(key, RVK_COPY)) {
906 a31a7b29 2014-11-15 marcelgmr if (rover.marks.nentries)
907 a31a7b29 2014-11-15 marcelgmr process_marked(adddir, cpyfile, NULL);
908 a31a7b29 2014-11-15 marcelgmr else message("No entries marked for copying.", RED);
909 a31a7b29 2014-11-15 marcelgmr }
910 a31a7b29 2014-11-15 marcelgmr else if (!strcmp(key, RVK_MOVE)) {
911 a31a7b29 2014-11-15 marcelgmr if (rover.marks.nentries)
912 a31a7b29 2014-11-15 marcelgmr process_marked(adddir, movfile, deldir);
913 a31a7b29 2014-11-15 marcelgmr else message("No entries marked for moving.", RED);
914 a31a7b29 2014-11-15 marcelgmr }
915 576e768d 2014-11-08 marcelgmr }
916 18016333 2014-11-14 marcelgmr if (rover.nfiles)
917 18016333 2014-11-14 marcelgmr free_rows(&rover.rows, rover.nfiles);
918 c3758004 2014-11-15 marcelgmr free_marks(&rover.marks);
919 f05efd9e 2014-11-07 marcelgmr delwin(rover.window);
920 71ee1627 2014-11-07 marcelgmr return 0;
921 71ee1627 2014-11-07 marcelgmr }