Commit Diff


commit - d844e0fdb4eac05a992ed39d68c404d2afce7013
commit + c66e2de770c9fdc53143fea1fcc1e8b89f3933be
blob - eca6aebc7cbb18cacda010b7d6ee4799b3212035
blob + 04cf5047bbc2f6dbc12ea4abff21271ab0b843f2
--- fm.c
+++ fm.c
@@ -25,8 +25,10 @@
 
 #include "config.h"
 
-/*  This signal is not defined by POSIX, but should be
-   present on all systems that have resizable terminals. */
+/*
+ * This signal is not defined by POSIX, but should be present on all
+ * systems that have resizable terminals.
+ */
 #ifndef SIGWINCH
 #define SIGWINCH  28
 #endif
@@ -60,54 +62,54 @@ static char *user_open;
 
 /* Information associated to each entry in listing. */
 typedef struct Row {
-    char *name;
-    off_t size;
-    mode_t mode;
-    int islink;
-    int marked;
+	char *name;
+	off_t size;
+	mode_t mode;
+	int islink;
+	int marked;
 } Row;
 
 /* Dynamic array of marked entries. */
 typedef struct Marks {
-    char dirpath[PATH_MAX];
-    int bulk;
-    int nentries;
-    char **entries;
+	char dirpath[PATH_MAX];
+	int bulk;
+	int nentries;
+	char **entries;
 } Marks;
 
 /* Line editing state. */
 typedef struct Edit {
-    wchar_t buffer[BUFLEN+1];
-    int left, right;
+	wchar_t buffer[BUFLEN + 1];
+	int left, right;
 } Edit;
 
 /* Each tab only stores the following information. */
 typedef struct Tab {
-    int scroll;
-    int esel;
-    uint8_t flags;
-    char cwd[PATH_MAX];
+	int scroll;
+	int esel;
+	uint8_t flags;
+	char cwd[PATH_MAX];
 } Tab;
 
 typedef struct Prog {
-    off_t partial;
-    off_t total;
-    const char *msg;
+	off_t partial;
+	off_t total;
+	const char *msg;
 } Prog;
 
 /* Global state. */
 static struct Rover {
-    int tab;
-    int nfiles;
-    Row *rows;
-    WINDOW *window;
-    Marks marks;
-    Edit edit;
-    int edit_scroll;
-    volatile sig_atomic_t pending_usr1;
-    volatile sig_atomic_t pending_winch;
-    Prog prog;
-    Tab tabs[10];
+	int tab;
+	int nfiles;
+	Row *rows;
+	WINDOW *window;
+	Marks marks;
+	Edit edit;
+	int edit_scroll;
+	volatile sig_atomic_t pending_usr1;
+	volatile sig_atomic_t pending_winch;
+	Prog prog;
+	Tab tabs[10];
 } rover;
 
 /* Macros for accessing global state. */
@@ -137,135 +139,136 @@ static struct Rover {
 #define EDIT_DELETE(E)     (E).right++
 #define EDIT_CLEAR(E)      do { (E).left = 0; (E).right = BUFLEN-1; } while(0)
 
-typedef enum EditStat {CONTINUE, CONFIRM, CANCEL} EditStat;
-typedef enum Color {DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, MAGENTA, WHITE, BLACK} Color;
+typedef enum EditStat { CONTINUE, CONFIRM, CANCEL } EditStat;
+typedef enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, MAGENTA, WHITE, BLACK } Color;
 typedef int (*PROCESS)(const char *path);
 
 static void
 init_marks(Marks *marks)
 {
-    strcpy(marks->dirpath, "");
-    marks->bulk = BULK_INIT;
-    marks->nentries = 0;
-    marks->entries = calloc(marks->bulk, sizeof *marks->entries);
+	strcpy(marks->dirpath, "");
+	marks->bulk = BULK_INIT;
+	marks->nentries = 0;
+	marks->entries = calloc(marks->bulk, sizeof *marks->entries);
 }
 
 /* Unmark all entries. */
 static void
 mark_none(Marks *marks)
 {
-    int i;
+	int i;
 
-    strcpy(marks->dirpath, "");
-    for (i = 0; i < marks->bulk && marks->nentries; i++)
-        if (marks->entries[i]) {
-            free(marks->entries[i]);
-            marks->entries[i] = NULL;
-            marks->nentries--;
-        }
-    if (marks->bulk > BULK_THRESH) {
-        /* Reset bulk to free some memory. */
-        free(marks->entries);
-        marks->bulk = BULK_INIT;
-        marks->entries = calloc(marks->bulk, sizeof *marks->entries);
-    }
+	strcpy(marks->dirpath, "");
+	for (i = 0; i < marks->bulk && marks->nentries; i++)
+		if (marks->entries[i]) {
+			free(marks->entries[i]);
+			marks->entries[i] = NULL;
+			marks->nentries--;
+		}
+	if (marks->bulk > BULK_THRESH) {
+	        /* Reset bulk to free some memory. */
+		free(marks->entries);
+		marks->bulk = BULK_INIT;
+		marks->entries = calloc(marks->bulk, sizeof *marks->entries);
+	}
 }
 
 static void
 add_mark(Marks *marks, char *dirpath, char *entry)
 {
-    int i;
+	int i;
 
-    if (!strcmp(marks->dirpath, dirpath)) {
-        /* Append mark to directory. */
-        if (marks->nentries == marks->bulk) {
-            /* Expand bulk to accomodate new entry. */
-            int extra = marks->bulk / 2;
-            marks->bulk += extra; /* bulk *= 1.5; */
-            marks->entries = realloc(marks->entries,
-                                     marks->bulk * sizeof *marks->entries);
-            memset(&marks->entries[marks->nentries], 0,
-                   extra * sizeof *marks->entries);
-            i = marks->nentries;
-        } else {
-            /* Search for empty slot (there must be one). */
-            for (i = 0; i < marks->bulk; i++)
-                if (!marks->entries[i])
-                    break;
-        }
-    } else {
-        /* Directory changed. Discard old marks. */
-        mark_none(marks);
-        strcpy(marks->dirpath, dirpath);
-        i = 0;
-    }
-    marks->entries[i] = malloc(strlen(entry) + 1);
-    strcpy(marks->entries[i], entry);
-    marks->nentries++;
+	if (!strcmp(marks->dirpath, dirpath)) {
+        	/* Append mark to directory. */
+		if (marks->nentries == marks->bulk) {
+			/* Expand bulk to accomodate new entry. */
+			int extra = marks->bulk / 2;
+			marks->bulk += extra; /* bulk *= 1.5; */
+			marks->entries = realloc(marks->entries,
+			    marks->bulk * sizeof *marks->entries);
+			memset(&marks->entries[marks->nentries], 0,
+			    extra * sizeof *marks->entries);
+			i = marks->nentries;
+		} else {
+			/* Search for empty slot (there must be one). */
+			for (i = 0; i < marks->bulk; i++)
+				if (!marks->entries[i])
+					break;
+		}
+	} else {
+		/* Directory changed. Discard old marks. */
+		mark_none(marks);
+		strcpy(marks->dirpath, dirpath);
+		i = 0;
+	}
+	marks->entries[i] = malloc(strlen(entry) + 1);
+	strcpy(marks->entries[i], entry);
+	marks->nentries++;
 }
 
 static void
 del_mark(Marks *marks, char *entry)
 {
-    int i;
+	int i;
 
-    if (marks->nentries > 1) {
-        for (i = 0; i < marks->bulk; i++)
-            if (marks->entries[i] && !strcmp(marks->entries[i], entry))
-                break;
-        free(marks->entries[i]);
-        marks->entries[i] = NULL;
-        marks->nentries--;
-    } else
-        mark_none(marks);
+	if (marks->nentries > 1) {
+		for (i = 0; i < marks->bulk; i++)
+			if (marks->entries[i] &&
+			    !strcmp(marks->entries[i], entry))
+				break;
+		free(marks->entries[i]);
+		marks->entries[i] = NULL;
+		marks->nentries--;
+	} else
+		mark_none(marks);
 }
 
 static void
 free_marks(Marks *marks)
 {
-    int i;
+	int i;
 
-    for (i = 0; i < marks->bulk && marks->nentries; i++)
-        if (marks->entries[i]) {
-            free(marks->entries[i]);
-            marks->nentries--;
-        }
-    free(marks->entries);
+	for (i = 0; i < marks->bulk && marks->nentries; i++)
+		if (marks->entries[i]) {
+			free(marks->entries[i]);
+			marks->nentries--;
+		}
+	free(marks->entries);
 }
 
 static void
 handle_usr1(int sig)
 {
-    rover.pending_usr1 = 1;
+	rover.pending_usr1 = 1;
 }
 
 static void
 handle_winch(int sig)
 {
-    rover.pending_winch = 1;
+	rover.pending_winch = 1;
 }
 
 static void
 enable_handlers()
 {
-    struct sigaction sa;
+	struct sigaction sa;
 
-    memset(&sa, 0, sizeof (struct sigaction));
-    sa.sa_handler = handle_usr1;
-    sigaction(SIGUSR1, &sa, NULL);
-    sa.sa_handler = handle_winch;
-    sigaction(SIGWINCH, &sa, NULL);
+	memset(&sa, 0, sizeof(struct sigaction));
+	sa.sa_handler = handle_usr1;
+	sigaction(SIGUSR1, &sa, NULL);
+	sa.sa_handler = handle_winch;
+	sigaction(SIGWINCH, &sa, NULL);
 }
 
 static void
 disable_handlers()
 {
-    struct sigaction sa;
+	struct sigaction sa;
 
-    memset(&sa, 0, sizeof (struct sigaction));
-    sa.sa_handler = SIG_DFL;
-    sigaction(SIGUSR1, &sa, NULL);
-    sigaction(SIGWINCH, &sa, NULL);
+	memset(&sa, 0, sizeof(struct sigaction));
+	sa.sa_handler = SIG_DFL;
+	sigaction(SIGUSR1, &sa, NULL);
+	sigaction(SIGWINCH, &sa, NULL);
 }
 
 static void reload();
@@ -275,1226 +278,1340 @@ static void update_view();
 static void
 sync_signals()
 {
-    if (rover.pending_usr1) {
-        /* SIGUSR1 received: refresh directory listing. */
-        reload();
-        rover.pending_usr1 = 0;
-    }
-    if (rover.pending_winch) {
-        /* SIGWINCH received: resize application accordingly. */
-        delwin(rover.window);
-        endwin();
-        refresh();
-        clear();
-        rover.window = subwin(stdscr, LINES - 2, COLS, 1, 0);
-        if (HEIGHT < rover.nfiles && SCROLL + HEIGHT > rover.nfiles)
-            SCROLL = ESEL - HEIGHT;
-        update_view();
-        rover.pending_winch = 0;
-    }
+	if (rover.pending_usr1) {
+		/* SIGUSR1 received: refresh directory listing. */
+		reload();
+		rover.pending_usr1 = 0;
+	}
+	if (rover.pending_winch) {
+		/* SIGWINCH received: resize application accordingly. */
+		delwin(rover.window);
+		endwin();
+		refresh();
+		clear();
+		rover.window = subwin(stdscr, LINES - 2, COLS, 1, 0);
+		if (HEIGHT < rover.nfiles && SCROLL + HEIGHT > rover.nfiles)
+			SCROLL = ESEL - HEIGHT;
+		update_view();
+		rover.pending_winch = 0;
+	}
 }
 
-/* This function must be used in place of getch().
-   It handles signals while waiting for user input. */
+/*
+ * This function must be used in place of getch().  It handles signals
+ * while waiting for user input.
+ */
 static int
 rover_getch()
 {
-    int ch;
+	int ch;
 
-    while ((ch = getch()) == ERR)
-        sync_signals();
-    return ch;
+	while ((ch = getch()) == ERR)
+		sync_signals();
+	return ch;
 }
 
-/* This function must be used in place of get_wch().
-   It handles signals while waiting for user input. */
+/*
+ * This function must be used in place of get_wch().  It handles
+ * signals while waiting for user input.
+ */
 static int
 rover_get_wch(wint_t *wch)
 {
-    wint_t ret;
+	wint_t ret;
 
-    while ((ret = get_wch(wch)) == (wint_t) ERR)
-        sync_signals();
-    return ret;
+	while ((ret = get_wch(wch)) == (wint_t)ERR)
+		sync_signals();
+	return ret;
 }
 
 /* Get user programs from the environment. */
 
-#define ROVER_ENV(dst, src) if ((dst = getenv("ROVER_" #src)) == NULL) \
-                                dst = getenv(#src);
+#define ROVER_ENV(dst, src) if ((dst = getenv("ROVER_" #src)) == NULL)	\
+		dst = getenv(#src);
 
 static void
 get_user_programs()
 {
-    ROVER_ENV(user_shell, SHELL)
-    ROVER_ENV(user_pager, PAGER)
-    ROVER_ENV(user_editor, VISUAL)
-    if (!user_editor)
-        ROVER_ENV(user_editor, EDITOR)
-    ROVER_ENV(user_open, OPEN)
+	ROVER_ENV(user_shell, SHELL);
+	ROVER_ENV(user_pager, PAGER);
+	ROVER_ENV(user_editor, VISUAL);
+	if (!user_editor)
+		ROVER_ENV(user_editor, EDITOR);
+	ROVER_ENV(user_open, OPEN);
 }
 
 /* Do a fork-exec to external program (e.g. $EDITOR). */
 static void
 spawn(char **args)
 {
-    pid_t pid;
-    int status;
+	pid_t pid;
+	int status;
 
-    setenv("RVSEL", rover.nfiles ? ENAME(ESEL) : "", 1);
-    pid = fork();
-    if (pid > 0) {
-        /* fork() succeeded. */
-        disable_handlers();
-        endwin();
-        waitpid(pid, &status, 0);
-        enable_handlers();
-        kill(getpid(), SIGWINCH);
-    } else if (pid == 0) {
-        /* Child process. */
-        execvp(args[0], args);
-    }
+	setenv("RVSEL", rover.nfiles ? ENAME(ESEL) : "", 1);
+	pid = fork();
+	if (pid > 0) {
+		/* fork() succeeded. */
+		disable_handlers();
+		endwin();
+		waitpid(pid, &status, 0);
+		enable_handlers();
+		kill(getpid(), SIGWINCH);
+	} else if (pid == 0) {
+		/* Child process. */
+		execvp(args[0], args);
+	}
 }
 
 static void
 shell_escaped_cat(char *buf, char *str, size_t n)
 {
-    char *p = buf + strlen(buf);
-    *p++ = '\'';
-    for (n--; n; n--, str++) {
-        switch (*str) {
-        case '\'':
-            if (n < 4)
-                goto done;
-            strcpy(p, "'\\''");
-            n -= 4;
-            p += 4;
-            break;
-        case '\0':
-            goto done;
-        default:
-            *p = *str;
-            p++;
-        }
-    }
+	char *p = buf + strlen(buf);
+	*p++ = '\'';
+	for (n--; n; n--, str++) {
+		switch (*str) {
+		case '\'':
+			if (n < 4)
+				goto done;
+			strcpy(p, "'\\''");
+			n -= 4;
+			p += 4;
+			break;
+		case '\0':
+			goto done;
+		default:
+			*p = *str;
+			p++;
+		}
+	}
 done:
-    strncat(p, "'", n);
+	strncat(p, "'", n);
 }
 
 static int
 open_with_env(char *program, char *path)
 {
-    if (program) {
+	if (program) {
 #ifdef RV_SHELL
-        strncpy(BUF1, program, BUFLEN - 1);
-        strncat(BUF1, " ", BUFLEN - strlen(program) - 1);
-        shell_escaped_cat(BUF1, path, BUFLEN - strlen(program) - 2);
-        spawn((char *[]) {RV_SHELL, "-c", BUF1, NULL});
+		strncpy(BUF1, program, BUFLEN - 1);
+		strncat(BUF1, " ", BUFLEN - strlen(program) - 1);
+		shell_escaped_cat(BUF1, path, BUFLEN - strlen(program) - 2);
+		spawn((char *[]) { RV_SHELL, "-c", BUF1, NULL });
 #else
-        spawn((char *[]) {program, path, NULL});
+		spawn((char *[]) { program, path, NULL });
 #endif
-        return 1;
-    }
-    return 0;
+		return 1;
+	}
+	return 0;
 }
 
 /* Curses setup. */
 static void
 init_term()
 {
-    setlocale(LC_ALL, "");
-    initscr();
-    cbreak(); /* Get one character at a time. */
-    timeout(100); /* For getch(). */
-    noecho();
-    nonl(); /* No NL->CR/NL on output. */
-    intrflush(stdscr, FALSE);
-    keypad(stdscr, TRUE);
-    curs_set(FALSE); /* Hide blinking cursor. */
-    if (has_colors()) {
-        short bg;
-        start_color();
+	setlocale(LC_ALL, "");
+	initscr();
+	cbreak(); /* Get one character at a time. */
+	timeout(100); /* For getch(). */
+	noecho();
+	nonl(); /* No NL->CR/NL on output. */
+	intrflush(stdscr, FALSE);
+	keypad(stdscr, TRUE);
+	curs_set(FALSE); /* Hide blinking cursor. */
+	if (has_colors()) {
+		short bg;
+		start_color();
 #ifdef NCURSES_EXT_FUNCS
-        use_default_colors();
-        bg = -1;
+		use_default_colors();
+		bg = -1;
 #else
-        bg = COLOR_BLACK;
+		bg = COLOR_BLACK;
 #endif
-        init_pair(RED, COLOR_RED, bg);
-        init_pair(GREEN, COLOR_GREEN, bg);
-        init_pair(YELLOW, COLOR_YELLOW, bg);
-        init_pair(BLUE, COLOR_BLUE, bg);
-        init_pair(CYAN, COLOR_CYAN, bg);
-        init_pair(MAGENTA, COLOR_MAGENTA, bg);
-        init_pair(WHITE, COLOR_WHITE, bg);
-        init_pair(BLACK, COLOR_BLACK, bg);
-    }
-    atexit((void (*)(void)) endwin);
-    enable_handlers();
+		init_pair(RED, COLOR_RED, bg);
+		init_pair(GREEN, COLOR_GREEN, bg);
+		init_pair(YELLOW, COLOR_YELLOW, bg);
+		init_pair(BLUE, COLOR_BLUE, bg);
+		init_pair(CYAN, COLOR_CYAN, bg);
+		init_pair(MAGENTA, COLOR_MAGENTA, bg);
+		init_pair(WHITE, COLOR_WHITE, bg);
+		init_pair(BLACK, COLOR_BLACK, bg);
+	}
+	atexit((void (*)(void))endwin);
+	enable_handlers();
 }
 
 /* Update the listing view. */
 static void
 update_view()
 {
-    int i, j;
-    int numsize;
-    int ishidden;
-    int marking;
+	int i, j;
+	int numsize;
+	int ishidden;
+	int marking;
 
-    mvhline(0, 0, ' ', COLS);
-    attr_on(A_BOLD, NULL);
-    color_set(RVC_TABNUM, NULL);
-    mvaddch(0, COLS - 2, rover.tab + '0');
-    attr_off(A_BOLD, NULL);
-    if (rover.marks.nentries) {
-        numsize = snprintf(BUF1, BUFLEN, "%d", rover.marks.nentries);
-        color_set(RVC_MARKS, NULL);
-        mvaddstr(0, COLS - 3 - numsize, BUF1);
-    } else
-        numsize = -1;
-    color_set(RVC_CWD, NULL);
-    mbstowcs(WBUF, CWD, PATH_MAX);
-    mvaddnwstr(0, 0, WBUF, COLS - 4 - numsize);
-    wcolor_set(rover.window, RVC_BORDER, NULL);
-    wborder(rover.window, 0, 0, 0, 0, 0, 0, 0, 0);
-    ESEL = MAX(MIN(ESEL, rover.nfiles - 1), 0);
-    /* Selection might not be visible, due to cursor wrapping or window
-       shrinking. In that case, the scroll must be moved to make it visible. */
-    if (rover.nfiles > HEIGHT) {
-        SCROLL = MAX(MIN(SCROLL, ESEL), ESEL - HEIGHT + 1);
-        SCROLL = MIN(MAX(SCROLL, 0), rover.nfiles - HEIGHT);
-    } else
-        SCROLL = 0;
-    marking = !strcmp(CWD, rover.marks.dirpath);
-    for (i = 0, j = SCROLL; i < HEIGHT && j < rover.nfiles; i++, j++) {
-        ishidden = ENAME(j)[0] == '.';
-        if (j == ESEL)
-            wattr_on(rover.window, A_REVERSE, NULL);
-        if (ISLINK(j))
-            wcolor_set(rover.window, RVC_LINK, NULL);
-        else if (ishidden)
-            wcolor_set(rover.window, RVC_HIDDEN, NULL);
-        else if (S_ISREG(EMODE(j))) {
-            if (EMODE(j) & (S_IXUSR | S_IXGRP | S_IXOTH))
-                wcolor_set(rover.window, RVC_EXEC, NULL);
-            else
-                wcolor_set(rover.window, RVC_REG, NULL);
-        } else if (S_ISDIR(EMODE(j)))
-            wcolor_set(rover.window, RVC_DIR, NULL);
-        else if (S_ISCHR(EMODE(j)))
-            wcolor_set(rover.window, RVC_CHR, NULL);
-        else if (S_ISBLK(EMODE(j)))
-            wcolor_set(rover.window, RVC_BLK, NULL);
-        else if (S_ISFIFO(EMODE(j)))
-            wcolor_set(rover.window, RVC_FIFO, NULL);
-        else if (S_ISSOCK(EMODE(j)))
-            wcolor_set(rover.window, RVC_SOCK, NULL);
-        if (S_ISDIR(EMODE(j))) {
-            mbstowcs(WBUF, ENAME(j), PATH_MAX);
-            if (ISLINK(j))
-                wcscat(WBUF, L"/");
-        } else {
-            char *suffix, *suffixes = "BKMGTPEZY";
-            off_t human_size = ESIZE(j) * 10;
-            int length = mbstowcs(WBUF, ENAME(j), PATH_MAX);
-            int namecols = wcswidth(WBUF, length);
-            for (suffix = suffixes; human_size >= 10240; suffix++)
-                human_size = (human_size + 512) / 1024;
-            if (*suffix == 'B')
-                swprintf(WBUF + length, PATH_MAX - length, L"%*d %c",
-                         (int) (COLS - namecols - 6),
-                         (int) human_size / 10, *suffix);
-            else
-                swprintf(WBUF + length, PATH_MAX - length, L"%*d.%d %c",
-                         (int) (COLS - namecols - 8),
-                         (int) human_size / 10, (int) human_size % 10, *suffix);
-        }
-        mvwhline(rover.window, i + 1, 1, ' ', COLS - 2);
-        mvwaddnwstr(rover.window, i + 1, 2, WBUF, COLS - 4);
-        if (marking && MARKED(j)) {
-            wcolor_set(rover.window, RVC_MARKS, NULL);
-            mvwaddch(rover.window, i + 1, 1, RVS_MARK);
-        } else
-            mvwaddch(rover.window, i + 1, 1, ' ');
-        if (j == ESEL)
-            wattr_off(rover.window, A_REVERSE, NULL);
-    }
-    for (; i < HEIGHT; i++)
-        mvwhline(rover.window, i + 1, 1, ' ', COLS - 2);
-    if (rover.nfiles > HEIGHT) {
-        int center, height;
-        center = (SCROLL + HEIGHT / 2) * HEIGHT / rover.nfiles;
-        height = (HEIGHT-1) * HEIGHT / rover.nfiles;
-        if (!height) height = 1;
-        wcolor_set(rover.window, RVC_SCROLLBAR, NULL);
-        mvwvline(rover.window, center-height/2+1, COLS-1, RVS_SCROLLBAR, height);
-    }
-    BUF1[0] = FLAGS & SHOW_FILES  ? 'F' : ' ';
-    BUF1[1] = FLAGS & SHOW_DIRS   ? 'D' : ' ';
-    BUF1[2] = FLAGS & SHOW_HIDDEN ? 'H' : ' ';
-    if (!rover.nfiles)
-        strcpy(BUF2, "0/0");
-    else
-        snprintf(BUF2, BUFLEN, "%d/%d", ESEL + 1, rover.nfiles);
-    snprintf(BUF1+3, BUFLEN-3, "%12s", BUF2);
-    color_set(RVC_STATUS, NULL);
-    mvaddstr(LINES - 1, STATUSPOS, BUF1);
-    wrefresh(rover.window);
+	mvhline(0, 0, ' ', COLS);
+	attr_on(A_BOLD, NULL);
+	color_set(RVC_TABNUM, NULL);
+	mvaddch(0, COLS - 2, rover.tab + '0');
+	attr_off(A_BOLD, NULL);
+	if (rover.marks.nentries) {
+		numsize = snprintf(BUF1, BUFLEN, "%d", rover.marks.nentries);
+		color_set(RVC_MARKS, NULL);
+		mvaddstr(0, COLS - 3 - numsize, BUF1);
+	} else
+		numsize = -1;
+	color_set(RVC_CWD, NULL);
+	mbstowcs(WBUF, CWD, PATH_MAX);
+	mvaddnwstr(0, 0, WBUF, COLS - 4 - numsize);
+	wcolor_set(rover.window, RVC_BORDER, NULL);
+	wborder(rover.window, 0, 0, 0, 0, 0, 0, 0, 0);
+	ESEL = MAX(MIN(ESEL, rover.nfiles - 1), 0);
+
+	/*
+	 * Selection might not be visible, due to cursor wrapping or
+	 * window shrinking. In that case, the scroll must be moved to
+	 * make it visible.
+	 */
+	if (rover.nfiles > HEIGHT) {
+		SCROLL = MAX(MIN(SCROLL, ESEL), ESEL - HEIGHT + 1);
+		SCROLL = MIN(MAX(SCROLL, 0), rover.nfiles - HEIGHT);
+	} else
+		SCROLL = 0;
+	marking = !strcmp(CWD, rover.marks.dirpath);
+	for (i = 0, j = SCROLL; i < HEIGHT && j < rover.nfiles; i++, j++) {
+		ishidden = ENAME(j)[0] == '.';
+		if (j == ESEL)
+			wattr_on(rover.window, A_REVERSE, NULL);
+		if (ISLINK(j))
+			wcolor_set(rover.window, RVC_LINK, NULL);
+		else if (ishidden)
+			wcolor_set(rover.window, RVC_HIDDEN, NULL);
+		else if (S_ISREG(EMODE(j))) {
+			if (EMODE(j) & (S_IXUSR | S_IXGRP | S_IXOTH))
+				wcolor_set(rover.window, RVC_EXEC, NULL);
+			else
+				wcolor_set(rover.window, RVC_REG, NULL);
+		} else if (S_ISDIR(EMODE(j)))
+			wcolor_set(rover.window, RVC_DIR, NULL);
+		else if (S_ISCHR(EMODE(j)))
+			wcolor_set(rover.window, RVC_CHR, NULL);
+		else if (S_ISBLK(EMODE(j)))
+			wcolor_set(rover.window, RVC_BLK, NULL);
+		else if (S_ISFIFO(EMODE(j)))
+			wcolor_set(rover.window, RVC_FIFO, NULL);
+		else if (S_ISSOCK(EMODE(j)))
+			wcolor_set(rover.window, RVC_SOCK, NULL);
+		if (S_ISDIR(EMODE(j))) {
+			mbstowcs(WBUF, ENAME(j), PATH_MAX);
+			if (ISLINK(j))
+				wcscat(WBUF, L"/");
+		} else {
+			char *suffix, *suffixes = "BKMGTPEZY";
+			off_t human_size = ESIZE(j) * 10;
+			int length = mbstowcs(WBUF, ENAME(j), PATH_MAX);
+			int namecols = wcswidth(WBUF, length);
+			for (suffix = suffixes; human_size >= 10240; suffix++)
+				human_size = (human_size + 512) / 1024;
+			if (*suffix == 'B')
+				swprintf(WBUF + length, PATH_MAX - length,
+				    L"%*d %c",
+				    (int)(COLS - namecols - 6),
+				    (int)human_size / 10, *suffix);
+			else
+				swprintf(WBUF + length, PATH_MAX - length,
+				    L"%*d.%d %c",
+				    (int)(COLS - namecols - 8),
+				    (int)human_size / 10,
+				    (int)human_size % 10, *suffix);
+		}
+		mvwhline(rover.window, i + 1, 1, ' ', COLS - 2);
+		mvwaddnwstr(rover.window, i + 1, 2, WBUF, COLS - 4);
+		if (marking && MARKED(j)) {
+			wcolor_set(rover.window, RVC_MARKS, NULL);
+			mvwaddch(rover.window, i + 1, 1, RVS_MARK);
+		} else
+			mvwaddch(rover.window, i + 1, 1, ' ');
+		if (j == ESEL)
+			wattr_off(rover.window, A_REVERSE, NULL);
+	}
+	for (; i < HEIGHT; i++)
+		mvwhline(rover.window, i + 1, 1, ' ', COLS - 2);
+	if (rover.nfiles > HEIGHT) {
+		int center, height;
+		center = (SCROLL + HEIGHT / 2) * HEIGHT / rover.nfiles;
+		height = (HEIGHT - 1) * HEIGHT / rover.nfiles;
+		if (!height)
+			height = 1;
+		wcolor_set(rover.window, RVC_SCROLLBAR, NULL);
+		mvwvline(rover.window, center - height/2 + 1, COLS - 1,
+		    RVS_SCROLLBAR, height);
+	}
+	BUF1[0] = FLAGS & SHOW_FILES ? 'F' : ' ';
+	BUF1[1] = FLAGS & SHOW_DIRS ? 'D' : ' ';
+	BUF1[2] = FLAGS & SHOW_HIDDEN ? 'H' : ' ';
+	if (!rover.nfiles)
+		strcpy(BUF2, "0/0");
+	else
+		snprintf(BUF2, BUFLEN, "%d/%d", ESEL + 1, rover.nfiles);
+	snprintf(BUF1 + 3, BUFLEN - 3, "%12s", BUF2);
+	color_set(RVC_STATUS, NULL);
+	mvaddstr(LINES - 1, STATUSPOS, BUF1);
+	wrefresh(rover.window);
 }
 
 /* Show a message on the status bar. */
 static void
 message(Color color, char *fmt, ...)
 {
-    int len, pos;
-    va_list args;
+	int len, pos;
+	va_list args;
 
-    va_start(args, fmt);
-    vsnprintf(BUF1, MIN(BUFLEN, STATUSPOS), fmt, args);
-    va_end(args);
-    len = strlen(BUF1);
-    pos = (STATUSPOS - len) / 2;
-    attr_on(A_BOLD, NULL);
-    color_set(color, NULL);
-    mvaddstr(LINES - 1, pos, BUF1);
-    color_set(DEFAULT, NULL);
-    attr_off(A_BOLD, NULL);
+	va_start(args, fmt);
+	vsnprintf(BUF1, MIN(BUFLEN, STATUSPOS), fmt, args);
+	va_end(args);
+	len = strlen(BUF1);
+	pos = (STATUSPOS - len) / 2;
+	attr_on(A_BOLD, NULL);
+	color_set(color, NULL);
+	mvaddstr(LINES - 1, pos, BUF1);
+	color_set(DEFAULT, NULL);
+	attr_off(A_BOLD, NULL);
 }
 
 /* Clear message area, leaving only status info. */
 static void
 clear_message()
 {
-    mvhline(LINES - 1, 0, ' ', STATUSPOS);
+	mvhline(LINES - 1, 0, ' ', STATUSPOS);
 }
 
 /* Comparison used to sort listing entries. */
 static int
 rowcmp(const void *a, const void *b)
 {
-    int isdir1, isdir2, cmpdir;
-    const Row *r1 = a;
-    const Row *r2 = b;
-    isdir1 = S_ISDIR(r1->mode);
-    isdir2 = S_ISDIR(r2->mode);
-    cmpdir = isdir2 - isdir1;
-    return cmpdir ? cmpdir : strcoll(r1->name, r2->name);
+	int isdir1, isdir2, cmpdir;
+	const Row *r1 = a;
+	const Row *r2 = b;
+	isdir1 = S_ISDIR(r1->mode);
+	isdir2 = S_ISDIR(r2->mode);
+	cmpdir = isdir2 - isdir1;
+	return cmpdir ? cmpdir : strcoll(r1->name, r2->name);
 }
 
 /* Get all entries in current working directory. */
 static int
 ls(Row **rowsp, uint8_t flags)
 {
-    DIR *dp;
-    struct dirent *ep;
-    struct stat statbuf;
-    Row *rows;
-    int i, n;
+	DIR *dp;
+	struct dirent *ep;
+	struct stat statbuf;
+	Row *rows;
+	int i, n;
 
-    if(!(dp = opendir("."))) return -1;
-    n = -2; /* We don't want the entries "." and "..". */
-    while (readdir(dp)) n++;
-    if (n == 0) {
-        closedir(dp);
-        return 0;
-    }
-    rewinddir(dp);
-    rows = malloc(n * sizeof *rows);
-    i = 0;
-    while ((ep = readdir(dp))) {
-        if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
-            continue;
-        if (!(flags & SHOW_HIDDEN) && ep->d_name[0] == '.')
-            continue;
-        lstat(ep->d_name, &statbuf);
-        rows[i].islink = S_ISLNK(statbuf.st_mode);
-        stat(ep->d_name, &statbuf);
-        if (S_ISDIR(statbuf.st_mode)) {
-            if (flags & SHOW_DIRS) {
-                rows[i].name = malloc(strlen(ep->d_name) + 2);
-                strcpy(rows[i].name, ep->d_name);
-                if (!rows[i].islink)
-                    strcat(rows[i].name, "/");
-                rows[i].mode = statbuf.st_mode;
-                i++;
-            }
-        } else if (flags & SHOW_FILES) {
-            rows[i].name = malloc(strlen(ep->d_name) + 1);
-            strcpy(rows[i].name, ep->d_name);
-            rows[i].size = statbuf.st_size;
-            rows[i].mode = statbuf.st_mode;
-            i++;
-        }
-    }
-    n = i; /* Ignore unused space in array caused by filters. */
-    qsort(rows, n, sizeof (*rows), rowcmp);
-    closedir(dp);
-    *rowsp = rows;
-    return n;
+	if (!(dp = opendir(".")))
+		return -1;
+	n = -2; /* We don't want the entries "." and "..". */
+	while (readdir(dp))
+		n++;
+	if (n == 0) {
+		closedir(dp);
+		return 0;
+	}
+	rewinddir(dp);
+	rows = malloc(n * sizeof *rows);
+	i = 0;
+	while ((ep = readdir(dp))) {
+		if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
+			continue;
+		if (!(flags & SHOW_HIDDEN) && ep->d_name[0] == '.')
+			continue;
+		lstat(ep->d_name, &statbuf);
+		rows[i].islink = S_ISLNK(statbuf.st_mode);
+		stat(ep->d_name, &statbuf);
+		if (S_ISDIR(statbuf.st_mode)) {
+			if (flags & SHOW_DIRS) {
+				rows[i].name = malloc(strlen(ep->d_name) + 2);
+				strcpy(rows[i].name, ep->d_name);
+				if (!rows[i].islink)
+					strcat(rows[i].name, "/");
+				rows[i].mode = statbuf.st_mode;
+				i++;
+			}
+		} else if (flags & SHOW_FILES) {
+			rows[i].name = malloc(strlen(ep->d_name) + 1);
+			strcpy(rows[i].name, ep->d_name);
+			rows[i].size = statbuf.st_size;
+			rows[i].mode = statbuf.st_mode;
+			i++;
+		}
+	}
+	n = i; /* Ignore unused space in array caused by filters. */
+	qsort(rows, n, sizeof(*rows), rowcmp);
+	closedir(dp);
+	*rowsp = rows;
+	return n;
 }
 
 static void
 free_rows(Row **rowsp, int nfiles)
 {
-    int i;
+	int i;
 
-    for (i = 0; i < nfiles; i++)
-        free((*rowsp)[i].name);
-    free(*rowsp);
-    *rowsp = NULL;
+	for (i = 0; i < nfiles; i++)
+		free((*rowsp)[i].name);
+	free(*rowsp);
+	*rowsp = NULL;
 }
 
 /* Change working directory to the path in CWD. */
 static void
 cd(int reset)
 {
-    int i, j;
+	int i, j;
 
-    message(CYAN, "Loading \"%s\"...", CWD);
-    refresh();
-    if (chdir(CWD) == -1) {
-        getcwd(CWD, PATH_MAX-1);
-        if (CWD[strlen(CWD)-1] != '/')
-            strcat(CWD, "/");
-        goto done;
-    }
-    if (reset) ESEL = SCROLL = 0;
-    if (rover.nfiles)
-        free_rows(&rover.rows, rover.nfiles);
-    rover.nfiles = ls(&rover.rows, FLAGS);
-    if (!strcmp(CWD, rover.marks.dirpath)) {
-        for (i = 0; i < rover.nfiles; i++) {
-            for (j = 0; j < rover.marks.bulk; j++)
-                if (
-                    rover.marks.entries[j] &&
-                    !strcmp(rover.marks.entries[j], ENAME(i))
-                )
-                    break;
-            MARKED(i) = j < rover.marks.bulk;
-        }
-    } else
-        for (i = 0; i < rover.nfiles; i++)
-            MARKED(i) = 0;
+	message(CYAN, "Loading \"%s\"...", CWD);
+	refresh();
+	if (chdir(CWD) == -1) {
+		getcwd(CWD, PATH_MAX - 1);
+		if (CWD[strlen(CWD) - 1] != '/')
+			strcat(CWD, "/");
+		goto done;
+	}
+	if (reset)
+		ESEL = SCROLL = 0;
+	if (rover.nfiles)
+		free_rows(&rover.rows, rover.nfiles);
+	rover.nfiles = ls(&rover.rows, FLAGS);
+	if (!strcmp(CWD, rover.marks.dirpath)) {
+		for (i = 0; i < rover.nfiles; i++) {
+			for (j = 0; j < rover.marks.bulk; j++)
+				if (rover.marks.entries[j] &&
+				    !strcmp(rover.marks.entries[j], ENAME(i)))
+					break;
+			MARKED(i) = j < rover.marks.bulk;
+		}
+	} else
+		for (i = 0; i < rover.nfiles; i++)
+			MARKED(i) = 0;
 done:
-    clear_message();
-    update_view();
+	clear_message();
+	update_view();
 }
 
 /* Select a target entry, if it is present. */
 static void
 try_to_sel(const char *target)
 {
-    ESEL = 0;
-    if (!ISDIR(target))
-        while ((ESEL+1) < rover.nfiles && S_ISDIR(EMODE(ESEL)))
-            ESEL++;
-    while ((ESEL+1) < rover.nfiles && strcoll(ENAME(ESEL), target) < 0)
-        ESEL++;
+	ESEL = 0;
+	if (!ISDIR(target))
+		while ((ESEL + 1) < rover.nfiles && S_ISDIR(EMODE(ESEL)))
+			ESEL++;
+	while ((ESEL + 1) < rover.nfiles && strcoll(ENAME(ESEL), target) < 0)
+		ESEL++;
 }
 
 /* Reload CWD, but try to keep selection. */
 static void
 reload()
 {
-    if (rover.nfiles) {
-        strcpy(INPUT, ENAME(ESEL));
-        cd(0);
-        try_to_sel(INPUT);
-        update_view();
-    } else
-        cd(1);
+	if (rover.nfiles) {
+		strcpy(INPUT, ENAME(ESEL));
+		cd(0);
+		try_to_sel(INPUT);
+		update_view();
+	} else
+		cd(1);
 }
 
 static off_t
 count_dir(const char *path)
 {
-    DIR *dp;
-    struct dirent *ep;
-    struct stat statbuf;
-    char subpath[PATH_MAX];
-    off_t total;
+	DIR *dp;
+	struct dirent *ep;
+	struct stat statbuf;
+	char subpath[PATH_MAX];
+	off_t total;
 
-    if(!(dp = opendir(path))) return 0;
-    total = 0;
-    while ((ep = readdir(dp))) {
-        if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
-            continue;
-        snprintf(subpath, PATH_MAX, "%s%s", path, ep->d_name);
-        lstat(subpath, &statbuf);
-        if (S_ISDIR(statbuf.st_mode)) {
-            strcat(subpath, "/");
-            total += count_dir(subpath);
-        } else
-            total += statbuf.st_size;
-    }
-    closedir(dp);
-    return total;
+	if (!(dp = opendir(path)))
+		return 0;
+	total = 0;
+	while ((ep = readdir(dp))) {
+		if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
+			continue;
+		snprintf(subpath, PATH_MAX, "%s%s", path, ep->d_name);
+		lstat(subpath, &statbuf);
+		if (S_ISDIR(statbuf.st_mode)) {
+			strcat(subpath, "/");
+			total += count_dir(subpath);
+		} else
+			total += statbuf.st_size;
+	}
+	closedir(dp);
+	return total;
 }
 
 static off_t
 count_marked()
 {
-    int i;
-    char *entry;
-    off_t total;
-    struct stat statbuf;
+	int i;
+	char *entry;
+	off_t total;
+	struct stat statbuf;
 
-    total = 0;
-    chdir(rover.marks.dirpath);
-    for (i = 0; i < rover.marks.bulk; i++) {
-        entry = rover.marks.entries[i];
-        if (entry) {
-            if (ISDIR(entry)) {
-                total += count_dir(entry);
-            } else {
-                lstat(entry, &statbuf);
-                total += statbuf.st_size;
-            }
-        }
-    }
-    chdir(CWD);
-    return total;
+	total = 0;
+	chdir(rover.marks.dirpath);
+	for (i = 0; i < rover.marks.bulk; i++) {
+		entry = rover.marks.entries[i];
+		if (entry) {
+			if (ISDIR(entry)) {
+				total += count_dir(entry);
+			} else {
+				lstat(entry, &statbuf);
+				total += statbuf.st_size;
+			}
+		}
+	}
+	chdir(CWD);
+	return total;
 }
 
-/* Recursively process a source directory using CWD as destination root.
-   For each node (i.e. directory), do the following:
-    1. call pre(destination);
-    2. call proc() on every child leaf (i.e. files);
-    3. recurse into every child node;
-    4. call pos(source).
-   E.g. to move directory /src/ (and all its contents) inside /dst/:
-    strcpy(CWD, "/dst/");
-    process_dir(adddir, movfile, deldir, "/src/"); */
+/*
+ * Recursively process a source directory using CWD as destination
+ * root.  For each node (i.e. directory), do the following:
+ *
+ * 1. call pre(destination);
+ * 2. call proc() on every child leaf (i.e. files);
+ * 3. recurse into every child node;
+ * 4. call pos(source).
+ *
+ * E.g. to move directory /src/ (and all its contents) inside /dst/:
+ * strcpy(CWD, "/dst/");
+ * process_dir(adddir, movfile, deldir, "/src/");
+ */
 static int
 process_dir(PROCESS pre, PROCESS proc, PROCESS pos, const char *path)
 {
-    int ret;
-    DIR *dp;
-    struct dirent *ep;
-    struct stat statbuf;
-    char subpath[PATH_MAX];
+	int ret;
+	DIR *dp;
+	struct dirent *ep;
+	struct stat statbuf;
+	char subpath[PATH_MAX];
 
-    ret = 0;
-    if (pre) {
-        char dstpath[PATH_MAX];
-        strcpy(dstpath, CWD);
-        strcat(dstpath, path + strlen(rover.marks.dirpath));
-        ret |= pre(dstpath);
-    }
-    if(!(dp = opendir(path))) return -1;
-    while ((ep = readdir(dp))) {
-        if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
-            continue;
-        snprintf(subpath, PATH_MAX, "%s%s", path, ep->d_name);
-        lstat(subpath, &statbuf);
-        if (S_ISDIR(statbuf.st_mode)) {
-            strcat(subpath, "/");
-            ret |= process_dir(pre, proc, pos, subpath);
-        } else
-            ret |= proc(subpath);
-    }
-    closedir(dp);
-    if (pos) ret |= pos(path);
-    return ret;
-}
-
-/* Process all marked entries using CWD as destination root.
-   All marked entries that are directories will be recursively processed.
-   See process_dir() for details on the parameters. */
-static void
-process_marked(PROCESS pre, PROCESS proc, PROCESS pos,
-               const char *msg_doing, const char *msg_done)
-{
-    int i, ret;
-    char *entry;
-    char path[PATH_MAX];
-
-    clear_message();
-    message(CYAN, "%s...", msg_doing);
-    refresh();
-    rover.prog = (Prog) {0, count_marked(), msg_doing};
-    for (i = 0; i < rover.marks.bulk; i++) {
-        entry = rover.marks.entries[i];
-        if (entry) {
-            ret = 0;
-            snprintf(path, PATH_MAX, "%s%s", rover.marks.dirpath, entry);
-            if (ISDIR(entry)) {
-                if (!strncmp(path, CWD, strlen(path)))
-                    ret = -1;
-                else
-                    ret = process_dir(pre, proc, pos, path);
-            } else
-                ret = proc(path);
-            if (!ret) {
-                del_mark(&rover.marks, entry);
-                reload();
-            }
-        }
-    }
-    rover.prog.total = 0;
-    reload();
-    if (!rover.marks.nentries)
-        message(GREEN, "%s all marked entries.", msg_done);
-    else
-        message(RED, "Some errors occured while %s.", msg_doing);
-    RV_ALERT();
+	ret = 0;
+	if (pre) {
+		char dstpath[PATH_MAX];
+		strcpy(dstpath, CWD);
+		strcat(dstpath, path + strlen(rover . marks . dirpath));
+		ret |= pre(dstpath);
+	}
+	if (!(dp = opendir(path)))
+		return -1;
+	while ((ep = readdir(dp))) {
+		if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
+			continue;
+		snprintf(subpath, PATH_MAX, "%s%s", path, ep->d_name);
+		lstat(subpath, &statbuf);
+		if (S_ISDIR(statbuf.st_mode)) {
+			strcat(subpath, "/");
+			ret |= process_dir(pre, proc, pos, subpath);
+		} else
+			ret |= proc(subpath);
+	}
+	closedir(dp);
+	if (pos)
+		ret |= pos(path);
+	return ret;
 }
 
+/*
+ * Process all marked entries using CWD as destination root.  All
+ * marked entries that are directories will be recursively processed.
+ * See process_dir() for details on the parameters.
+ */
 static void
+process_marked(PROCESS pre, PROCESS proc, PROCESS pos, const char *msg_doing,
+    const char *msg_done)
+{
+	int i, ret;
+	char *entry;
+	char path[PATH_MAX];
+
+	clear_message();
+	message(CYAN, "%s...", msg_doing);
+	refresh();
+	rover.prog = (Prog){0, count_marked(), msg_doing};
+	for (i = 0; i < rover.marks.bulk; i++) {
+		entry = rover.marks.entries[i];
+		if (entry) {
+			ret = 0;
+			snprintf(path, PATH_MAX, "%s%s", rover.marks.dirpath,
+			    entry);
+			if (ISDIR(entry)) {
+				if (!strncmp(path, CWD, strlen(path)))
+					ret = -1;
+				else
+					ret = process_dir(pre, proc, pos, path);
+			} else
+				ret = proc(path);
+			if (!ret) {
+				del_mark(&rover.marks, entry);
+				reload();
+			}
+		}
+	}
+	rover.prog.total = 0;
+	reload();
+	if (!rover.marks.nentries)
+		message(GREEN, "%s all marked entries.", msg_done);
+	else
+		message(RED, "Some errors occured while %s.", msg_doing);
+	RV_ALERT();
+}
+
+static void
 update_progress(off_t delta)
 {
-    int percent;
+	int percent;
 
-    if (!rover.prog.total) return;
-    rover.prog.partial += delta;
-    percent = (int) (rover.prog.partial * 100 / rover.prog.total);
-    message(CYAN, "%s...%d%%", rover.prog.msg, percent);
-    refresh();
+	if (!rover.prog.total)
+		return;
+	rover.prog.partial += delta;
+	percent = (int)(rover.prog.partial * 100 / rover.prog.total);
+	message(CYAN, "%s...%d%%", rover.prog.msg, percent);
+	refresh();
 }
 
 /* Wrappers for file operations. */
-static int delfile(const char *path) {
-    int ret;
-    struct stat st;
+static int
+delfile(const char *path)
+{
+	int ret;
+	struct stat st;
 
-    ret = lstat(path, &st);
-    if (ret < 0) return ret;
-    update_progress(st.st_size);
-    return unlink(path);
+	ret = lstat(path, &st);
+	if (ret < 0)
+		return ret;
+	update_progress(st.st_size);
+	return unlink(path);
 }
+
 static PROCESS deldir = rmdir;
-static int addfile(const char *path) {
-    /* Using creat(2) because mknod(2) doesn't seem to be portable. */
-    int ret;
+static int
+addfile(const char *path)
+{
+	/* Using creat(2) because mknod(2) doesn't seem to be portable. */
+	int ret;
 
-    ret = creat(path, 0644);
-    if (ret < 0) return ret;
-    return close(ret);
+	ret = creat(path, 0644);
+	if (ret < 0)
+		return ret;
+	return close(ret);
 }
-static int cpyfile(const char *srcpath) {
-    int src, dst, ret;
-    size_t size;
-    struct stat st;
-    char buf[BUFSIZ];
-    char dstpath[PATH_MAX];
 
-    strcpy(dstpath, CWD);
-    strcat(dstpath, srcpath + strlen(rover.marks.dirpath));
-    ret = lstat(srcpath, &st);
-    if (ret < 0) return ret;
-    if (S_ISLNK(st.st_mode)) {
-        ret = readlink(srcpath, BUF1, BUFLEN-1);
-        if (ret < 0) return ret;
-        BUF1[ret] = '\0';
-        ret = symlink(BUF1, dstpath);
-    } else {
-        ret = src = open(srcpath, O_RDONLY);
-        if (ret < 0) return ret;
-        ret = dst = creat(dstpath, st.st_mode);
-        if (ret < 0) return ret;
-        while ((size = read(src, buf, BUFSIZ)) > 0) {
-            write(dst, buf, size);
-            update_progress(size);
-            sync_signals();
-        }
-        close(src);
-        close(dst);
-        ret = 0;
-    }
-    return ret;
+static int
+cpyfile(const char *srcpath)
+{
+	int src, dst, ret;
+	size_t size;
+	struct stat st;
+	char buf[BUFSIZ];
+	char dstpath[PATH_MAX];
+
+	strcpy(dstpath, CWD);
+	strcat(dstpath, srcpath + strlen(rover.marks.dirpath));
+	ret = lstat(srcpath, &st);
+	if (ret < 0)
+		return ret;
+	if (S_ISLNK(st.st_mode)) {
+		ret = readlink(srcpath, BUF1, BUFLEN - 1);
+		if (ret < 0)
+			return ret;
+		BUF1[ret] = '\0';
+		ret = symlink(BUF1, dstpath);
+	} else {
+		ret = src = open(srcpath, O_RDONLY);
+		if (ret < 0)
+			return ret;
+		ret = dst = creat(dstpath, st.st_mode);
+		if (ret < 0)
+			return ret;
+		while ((size = read(src, buf, BUFSIZ)) > 0) {
+			write(dst, buf, size);
+			update_progress(size);
+			sync_signals();
+		}
+		close(src);
+		close(dst);
+		ret = 0;
+	}
+	return ret;
 }
-static int adddir(const char *path) {
-    int ret;
-    struct stat st;
 
-    ret = stat(CWD, &st);
-    if (ret < 0) return ret;
-    return mkdir(path, st.st_mode);
+static int
+adddir(const char *path)
+{
+	int ret;
+	struct stat st;
+
+	ret = stat(CWD, &st);
+	if (ret < 0)
+		return ret;
+	return mkdir(path, st.st_mode);
 }
-static int movfile(const char *srcpath) {
-    int ret;
-    struct stat st;
-    char dstpath[PATH_MAX];
 
-    strcpy(dstpath, CWD);
-    strcat(dstpath, srcpath + strlen(rover.marks.dirpath));
-    ret = rename(srcpath, dstpath);
-    if (ret == 0) {
-        ret = lstat(dstpath, &st);
-        if (ret < 0) return ret;
-        update_progress(st.st_size);
-    } else if (errno == EXDEV) {
-        ret = cpyfile(srcpath);
-        if (ret < 0) return ret;
-        ret = unlink(srcpath);
-    }
-    return ret;
+static int
+movfile(const char *srcpath)
+{
+	int ret;
+	struct stat st;
+	char dstpath[PATH_MAX];
+
+	strcpy(dstpath, CWD);
+	strcat(dstpath, srcpath + strlen(rover.marks.dirpath));
+	ret = rename(srcpath, dstpath);
+	if (ret == 0) {
+		ret = lstat(dstpath, &st);
+		if (ret < 0)
+			return ret;
+		update_progress(st.st_size);
+	} else if (errno == EXDEV) {
+		ret = cpyfile(srcpath);
+		if (ret < 0)
+			return ret;
+		ret = unlink(srcpath);
+	}
+	return ret;
 }
 
 static void
 start_line_edit(const char *init_input)
 {
-    curs_set(TRUE);
-    strncpy(INPUT, init_input, BUFLEN);
-    rover.edit.left = mbstowcs(rover.edit.buffer, init_input, BUFLEN);
-    rover.edit.right = BUFLEN - 1;
-    rover.edit.buffer[BUFLEN] = L'\0';
-    rover.edit_scroll = 0;
+	curs_set(TRUE);
+	strncpy(INPUT, init_input, BUFLEN);
+	rover.edit.left = mbstowcs(rover.edit.buffer, init_input, BUFLEN);
+	rover.edit.right = BUFLEN - 1;
+	rover.edit.buffer[BUFLEN] = L'\0';
+	rover.edit_scroll = 0;
 }
 
 /* Read input and change editing state accordingly. */
 static EditStat
 get_line_edit()
 {
-    wchar_t eraser, killer, wch;
-    int ret, length;
+	wchar_t eraser, killer, wch;
+	int ret, length;
 
-    ret = rover_get_wch((wint_t *) &wch);
-    erasewchar(&eraser);
-    killwchar(&killer);
-    if (ret == KEY_CODE_YES) {
-        if (wch == KEY_ENTER) {
-            curs_set(FALSE);
-            return CONFIRM;
-        } else if (wch == KEY_LEFT) {
-            if (EDIT_CAN_LEFT(rover.edit)) EDIT_LEFT(rover.edit);
-        } else if (wch == KEY_RIGHT) {
-            if (EDIT_CAN_RIGHT(rover.edit)) EDIT_RIGHT(rover.edit);
-        } else if (wch == KEY_UP) {
-            while (EDIT_CAN_LEFT(rover.edit)) EDIT_LEFT(rover.edit);
-        } else if (wch == KEY_DOWN) {
-            while (EDIT_CAN_RIGHT(rover.edit)) EDIT_RIGHT(rover.edit);
-        } else if (wch == KEY_BACKSPACE) {
-            if (EDIT_CAN_LEFT(rover.edit)) EDIT_BACKSPACE(rover.edit);
-        } else if (wch == KEY_DC) {
-            if (EDIT_CAN_RIGHT(rover.edit)) EDIT_DELETE(rover.edit);
-        }
-    } else {
-        if (wch == L'\r' || wch == L'\n') {
-            curs_set(FALSE);
-            return CONFIRM;
-        } else if (wch == L'\t') {
-            curs_set(FALSE);
-            return CANCEL;
-        } else if (wch == eraser) {
-            if (EDIT_CAN_LEFT(rover.edit)) EDIT_BACKSPACE(rover.edit);
-        } else if (wch == killer) {
-            EDIT_CLEAR(rover.edit);
-            clear_message();
-        } else if (iswprint(wch)) {
-            if (!EDIT_FULL(rover.edit)) EDIT_INSERT(rover.edit, wch);
-        }
-    }
-    /* Encode edit contents in INPUT. */
-    rover.edit.buffer[rover.edit.left] = L'\0';
-    length = wcstombs(INPUT, rover.edit.buffer, BUFLEN);
-    wcstombs(&INPUT[length], &rover.edit.buffer[rover.edit.right+1],
-             BUFLEN-length);
-    return CONTINUE;
+	ret = rover_get_wch((wint_t *)&wch);
+	erasewchar(&eraser);
+	killwchar(&killer);
+	if (ret == KEY_CODE_YES) {
+		if (wch == KEY_ENTER) {
+			curs_set(FALSE);
+			return CONFIRM;
+		} else if (wch == KEY_LEFT) {
+			if (EDIT_CAN_LEFT(rover.edit))
+				EDIT_LEFT(rover.edit);
+		} else if (wch == KEY_RIGHT) {
+			if (EDIT_CAN_RIGHT(rover.edit))
+				EDIT_RIGHT(rover.edit);
+		} else if (wch == KEY_UP) {
+			while (EDIT_CAN_LEFT(rover.edit))
+				EDIT_LEFT(rover.edit);
+		} else if (wch == KEY_DOWN) {
+			while (EDIT_CAN_RIGHT(rover.edit))
+				EDIT_RIGHT(rover.edit);
+		} else if (wch == KEY_BACKSPACE) {
+			if (EDIT_CAN_LEFT(rover.edit))
+				EDIT_BACKSPACE(rover.edit);
+		} else if (wch == KEY_DC) {
+			if (EDIT_CAN_RIGHT(rover.edit))
+				EDIT_DELETE(rover.edit);
+		}
+	} else {
+		if (wch == L'\r' || wch == L'\n') {
+			curs_set(FALSE);
+			return CONFIRM;
+		} else if (wch == L'\t') {
+			curs_set(FALSE);
+			return CANCEL;
+		} else if (wch == eraser) {
+			if (EDIT_CAN_LEFT(rover.edit))
+				EDIT_BACKSPACE(rover.edit);
+		} else if (wch == killer) {
+			EDIT_CLEAR(rover.edit);
+			clear_message();
+		} else if (iswprint(wch)) {
+			if (!EDIT_FULL(rover.edit))
+				EDIT_INSERT(rover.edit, wch);
+		}
+	}
+	/* Encode edit contents in INPUT. */
+	rover.edit.buffer[rover.edit.left] = L'\0';
+	length = wcstombs(INPUT, rover.edit.buffer, BUFLEN);
+	wcstombs(&INPUT[length], &rover.edit.buffer[rover.edit.right + 1],
+	    BUFLEN - length);
+	return CONTINUE;
 }
 
 /* Update line input on the screen. */
 static void
 update_input(const char *prompt, Color color)
 {
-    int plen, ilen, maxlen;
+	int plen, ilen, maxlen;
 
-    plen = strlen(prompt);
-    ilen = mbstowcs(NULL, INPUT, 0);
-    maxlen = STATUSPOS - plen - 2;
-    if (ilen - rover.edit_scroll < maxlen)
-        rover.edit_scroll = MAX(ilen - maxlen, 0);
-    else if (rover.edit.left > rover.edit_scroll + maxlen - 1)
-        rover.edit_scroll = rover.edit.left - maxlen;
-    else if (rover.edit.left < rover.edit_scroll)
-        rover.edit_scroll = MAX(rover.edit.left - maxlen, 0);
-    color_set(RVC_PROMPT, NULL);
-    mvaddstr(LINES - 1, 0, prompt);
-    color_set(color, NULL);
-    mbstowcs(WBUF, INPUT, COLS);
-    mvaddnwstr(LINES - 1, plen, &WBUF[rover.edit_scroll], maxlen);
-    mvaddch(LINES - 1, plen + MIN(ilen - rover.edit_scroll, maxlen + 1), ' ');
-    color_set(DEFAULT, NULL);
-    if (rover.edit_scroll)
-        mvaddch(LINES - 1, plen - 1, '<');
-    if (ilen > rover.edit_scroll + maxlen)
-        mvaddch(LINES - 1, plen + maxlen, '>');
-    move(LINES - 1, plen + rover.edit.left - rover.edit_scroll);
+	plen = strlen(prompt);
+	ilen = mbstowcs(NULL, INPUT, 0);
+	maxlen = STATUSPOS - plen - 2;
+	if (ilen - rover.edit_scroll < maxlen)
+		rover.edit_scroll = MAX(ilen - maxlen, 0);
+	else if (rover.edit.left > rover.edit_scroll + maxlen - 1)
+		rover.edit_scroll = rover.edit.left - maxlen;
+	else if (rover.edit.left < rover.edit_scroll)
+		rover.edit_scroll = MAX(rover.edit.left - maxlen, 0);
+	color_set(RVC_PROMPT, NULL);
+	mvaddstr(LINES - 1, 0, prompt);
+	color_set(color, NULL);
+	mbstowcs(WBUF, INPUT, COLS);
+	mvaddnwstr(LINES - 1, plen, &WBUF[rover.edit_scroll], maxlen);
+	mvaddch(LINES - 1, plen + MIN(ilen - rover.edit_scroll, maxlen + 1),
+	    ' ');
+	color_set(DEFAULT, NULL);
+	if (rover.edit_scroll)
+		mvaddch(LINES - 1, plen - 1, '<');
+	if (ilen > rover.edit_scroll + maxlen)
+		mvaddch(LINES - 1, plen + maxlen, '>');
+	move(LINES - 1, plen + rover.edit.left - rover.edit_scroll);
 }
 
 int
 main(int argc, char *argv[])
 {
-    int i, ch;
-    char *program;
-    char *entry;
-    const char *key;
-    const char *clip_path;
-    DIR *d;
-    EditStat edit_stat;
-    FILE *save_cwd_file = NULL;
-    FILE *save_marks_file = NULL;
-    FILE *clip_file;
+	int i, ch;
+	char *program;
+	char *entry;
+	const char *key;
+	const char *clip_path;
+	DIR *d;
+	EditStat edit_stat;
+	FILE *save_cwd_file = NULL;
+	FILE *save_marks_file = NULL;
+	FILE *clip_file;
 
-    if (argc >= 2) {
-        if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) {
-            printf("rover %s\n", RV_VERSION);
-            return 0;
-        } else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
-            printf(
-                "Usage: rover [OPTIONS] [DIR [DIR [...]]]\n"
-                "       Browse current directory or the ones specified.\n\n"
-                "  or:  rover -h|--help\n"
-                "       Print this help message and exit.\n\n"
-                "  or:  rover -v|--version\n"
-                "       Print program version and exit.\n\n"
-                "See rover(1) for more information.\n"
-                "Rover homepage: <https://github.com/lecram/rover>.\n"
-            );
-            return 0;
-        } else if (!strcmp(argv[1], "-d") || !strcmp(argv[1], "--save-cwd")) {
-            if (argc > 2) {
-                save_cwd_file = fopen(argv[2], "w");
-                argc -= 2; argv += 2;
-            } else {
-                fprintf(stderr, "error: missing argument to %s\n", argv[1]);
-                return 1;
-            }
-        } else if (!strcmp(argv[1], "-m") || !strcmp(argv[1], "--save-marks")) {
-            if (argc > 2) {
-                save_marks_file = fopen(argv[2], "a");
-                argc -= 2; argv += 2;
-            } else {
-                fprintf(stderr, "error: missing argument to %s\n", argv[1]);
-                return 1;
-            }
-        }
-    }
-    get_user_programs();
-    init_term();
-    rover.nfiles = 0;
-    for (i = 0; i < 10; i++) {
-        rover.tabs[i].esel = rover.tabs[i].scroll = 0;
-        rover.tabs[i].flags = RV_FLAGS;
-    }
-    strcpy(rover.tabs[0].cwd, getenv("HOME"));
-    for (i = 1; i < argc && i < 10; i++) {
-        if ((d = opendir(argv[i]))) {
-            realpath(argv[i], rover.tabs[i].cwd);
-            closedir(d);
-        } else
-            strcpy(rover.tabs[i].cwd, rover.tabs[0].cwd);
-    }
-    getcwd(rover.tabs[i].cwd, PATH_MAX);
-    for (i++; i < 10; i++)
-        strcpy(rover.tabs[i].cwd, rover.tabs[i-1].cwd);
-    for (i = 0; i < 10; i++)
-        if (rover.tabs[i].cwd[strlen(rover.tabs[i].cwd) - 1] != '/')
-            strcat(rover.tabs[i].cwd, "/");
-    rover.tab = 1;
-    rover.window = subwin(stdscr, LINES - 2, COLS, 1, 0);
-    init_marks(&rover.marks);
-    cd(1);
-    strcpy(CLIPBOARD, CWD);
-    if (rover.nfiles > 0)
-        strcat(CLIPBOARD, ENAME(ESEL));
-    while (1) {
-        ch = rover_getch();
-        key = keyname(ch);
-        clear_message();
-        if (!strcmp(key, RVK_QUIT)) break;
-        else if (ch >= '0' && ch <= '9') {
-            rover.tab = ch - '0';
-            cd(0);
-        } else if (!strcmp(key, RVK_HELP)) {
-            spawn((char *[]) {"man", "rover", NULL});
-        } else if (!strcmp(key, RVK_DOWN)) {
-            if (!rover.nfiles) continue;
-            ESEL = MIN(ESEL + 1, rover.nfiles - 1);
-            update_view();
-        } else if (!strcmp(key, RVK_UP)) {
-            if (!rover.nfiles) continue;
-            ESEL = MAX(ESEL - 1, 0);
-            update_view();
-        } else if (!strcmp(key, RVK_JUMP_DOWN)) {
-            if (!rover.nfiles) continue;
-            ESEL = MIN(ESEL + RV_JUMP, rover.nfiles - 1);
-            if (rover.nfiles > HEIGHT)
-                SCROLL = MIN(SCROLL + RV_JUMP, rover.nfiles - HEIGHT);
-            update_view();
-        } else if (!strcmp(key, RVK_JUMP_UP)) {
-            if (!rover.nfiles) continue;
-            ESEL = MAX(ESEL - RV_JUMP, 0);
-            SCROLL = MAX(SCROLL - RV_JUMP, 0);
-            update_view();
-        } else if (!strcmp(key, RVK_JUMP_TOP)) {
-            if (!rover.nfiles) continue;
-            ESEL = 0;
-            update_view();
-        } else if (!strcmp(key, RVK_JUMP_BOTTOM)) {
-            if (!rover.nfiles) continue;
-            ESEL = rover.nfiles - 1;
-            update_view();
-        } else if (!strcmp(key, RVK_CD_DOWN)) {
-            if (!rover.nfiles || !S_ISDIR(EMODE(ESEL))) continue;
-            if (chdir(ENAME(ESEL)) == -1) {
-                message(RED, "Cannot access \"%s\".", ENAME(ESEL));
-                continue;
-            }
-            strcat(CWD, ENAME(ESEL));
-            cd(1);
-        } else if (!strcmp(key, RVK_CD_UP)) {
-            char *dirname, first;
-            if (!strcmp(CWD, "/")) continue;
-            CWD[strlen(CWD) - 1] = '\0';
-            dirname = strrchr(CWD, '/') + 1;
-            first = dirname[0];
-            dirname[0] = '\0';
-            cd(1);
-            dirname[0] = first;
-            dirname[strlen(dirname)] = '/';
-            try_to_sel(dirname);
-            dirname[0] = '\0';
-            if (rover.nfiles > HEIGHT)
-                SCROLL = ESEL - HEIGHT / 2;
-            update_view();
-        } else if (!strcmp(key, RVK_HOME)) {
-            strcpy(CWD, getenv("HOME"));
-            if (CWD[strlen(CWD) - 1] != '/')
-                strcat(CWD, "/");
-            cd(1);
-        } else if (!strcmp(key, RVK_TARGET)) {
-            char *bname, first;
-            int is_dir = S_ISDIR(EMODE(ESEL));
-            ssize_t len = readlink(ENAME(ESEL), BUF1, BUFLEN-1);
-            if (len == -1) continue;
-            BUF1[len] = '\0';
-            if (access(BUF1, F_OK) == -1) {
-                char *msg;
-                switch (errno) {
-                case EACCES:
-                    msg = "Cannot access \"%s\".";
-                    break;
-                case ENOENT:
-                    msg = "\"%s\" does not exist.";
-                    break;
-                default:
-                    msg = "Cannot navigate to \"%s\".";
-                }
-                strcpy(BUF2, BUF1); /* message() uses BUF1. */
-                message(RED, msg, BUF2);
-                continue;
-            }
-            realpath(BUF1, CWD);
-            len = strlen(CWD);
-            if (CWD[len - 1] == '/')
-                CWD[len - 1] = '\0';
-            bname = strrchr(CWD, '/') + 1;
-            first = *bname;
-            *bname = '\0';
-            cd(1);
-            *bname = first;
-            if (is_dir)
-                strcat(CWD, "/");
-            try_to_sel(bname);
-            *bname = '\0';
-            update_view();
-        } else if (!strcmp(key, RVK_COPY_PATH)) {
-            clip_path = getenv("CLIP");
-            if (!clip_path) goto copy_path_fail;
-            clip_file = fopen(clip_path, "w");
-            if (!clip_file) goto copy_path_fail;
-            fprintf(clip_file, "%s%s\n", CWD, ENAME(ESEL));
-            fclose(clip_file);
-            goto copy_path_done;
-copy_path_fail:
-            strcpy(CLIPBOARD, CWD);
-            strcat(CLIPBOARD, ENAME(ESEL));
-copy_path_done:
-            ;
-        } else if (!strcmp(key, RVK_PASTE_PATH)) {
-            clip_path = getenv("CLIP");
-            if (!clip_path) goto paste_path_fail;
-            clip_file = fopen(clip_path, "r");
-            if (!clip_file) goto paste_path_fail;
-            fscanf(clip_file, "%s\n", CLIPBOARD);
-            fclose(clip_file);
-paste_path_fail:
-            strcpy(BUF1, CLIPBOARD);
-            strcpy(CWD, dirname(BUF1));
-            if (strcmp(CWD, "/"))
-                strcat(CWD, "/");
-            cd(1);
-            strcpy(BUF1, CLIPBOARD);
-            try_to_sel(strstr(CLIPBOARD, basename(BUF1)));
-            update_view();
-        } else if (!strcmp(key, RVK_REFRESH)) {
-            reload();
-        } else if (!strcmp(key, RVK_SHELL)) {
-            program = user_shell;
-            if (program) {
-#ifdef RV_SHELL
-                spawn((char *[]) {RV_SHELL, "-c", program, NULL});
-#else
-                spawn((char *[]) {program, NULL});
+	if (argc >= 2) {
+		if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) {
+			printf("rover %s\n", RV_VERSION);
+			return 0;
+		} else if (!strcmp(argv[1], "-h") ||
+		    !strcmp(argv[1], "--help")) {
+			printf(
+				"Usage: rover [OPTIONS] [DIR [DIR [...]]]\n"
+				"       Browse current directory or the ones specified.\n\n"
+				"  or:  rover -h|--help\n"
+				"       Print this help message and exit.\n\n"
+				"  or:  rover -v|--version\n"
+				"       Print program version and exit.\n\n"
+				"See rover(1) for more information.\n"
+				"Rover homepage: <https://github.com/lecram/rover>.\n");
+			return 0;
+		} else if (!strcmp(argv[1], "-d") ||
+		    !strcmp(argv[1], "--save-cwd")) {
+			if (argc > 2) {
+				save_cwd_file = fopen(argv[2], "w");
+				argc -= 2;
+				argv += 2;
+			} else {
+				fprintf(stderr,
+				    "error: missing argument to %s\n", argv[1]);
+				return 1;
+			}
+		} else if (!strcmp(argv[1], "-m") ||
+		    !strcmp(argv[1], "--save-marks")) {
+			if (argc > 2) {
+				save_marks_file = fopen(argv[2], "a");
+				argc -= 2;
+				argv += 2;
+			} else {
+				fprintf(stderr,
+				    "error: missing argument to %s\n", argv[1]);
+				return 1;
+			}
+		}
+	}
+	get_user_programs();
+	init_term();
+	rover.nfiles = 0;
+	for (i = 0; i < 10; i++) {
+		rover.tabs[i].esel = rover.tabs[i].scroll = 0;
+		rover.tabs[i].flags = RV_FLAGS;
+	}
+	strcpy(rover.tabs[0].cwd, getenv("HOME"));
+	for (i = 1; i < argc && i < 10; i++) {
+		if ((d = opendir(argv[i]))) {
+			realpath(argv[i], rover.tabs[i].cwd);
+			closedir(d);
+		} else
+			strcpy(rover.tabs[i].cwd, rover.tabs[0].cwd);
+	}
+	getcwd(rover.tabs[i].cwd, PATH_MAX);
+	for (i++; i < 10; i++)
+		strcpy(rover.tabs[i].cwd, rover.tabs[i - 1].cwd);
+	for (i = 0; i < 10; i++)
+		if (rover.tabs[i].cwd[strlen(rover.tabs[i].cwd) - 1] != '/')
+			strcat(rover.tabs[i].cwd, "/");
+	rover.tab = 1;
+	rover.window = subwin(stdscr, LINES - 2, COLS, 1, 0);
+	init_marks(&rover.marks);
+	cd(1);
+	strcpy(CLIPBOARD, CWD);
+	if (rover.nfiles > 0)
+		strcat(CLIPBOARD, ENAME(ESEL));
+	while (1) {
+		ch = rover_getch();
+		key = keyname(ch);
+		clear_message();
+		if (!strcmp(key, RVK_QUIT))
+			break;
+		else if (ch >= '0' && ch <= '9') {
+			rover.tab = ch - '0';
+			cd(0);
+		} else if (!strcmp(key, RVK_HELP)) {
+			spawn((char *[]) { "man", "rover", NULL });
+		} else if (!strcmp(key, RVK_DOWN)) {
+			if (!rover.nfiles)
+				continue;
+			ESEL = MIN(ESEL + 1, rover.nfiles - 1);
+			update_view();
+		} else if (!strcmp(key, RVK_UP)) {
+			if (!rover.nfiles)
+				continue;
+			ESEL = MAX(ESEL - 1, 0);
+			update_view();
+		} else if (!strcmp(key, RVK_JUMP_DOWN)) {
+			if (!rover.nfiles)
+				continue;
+			ESEL = MIN(ESEL + RV_JUMP, rover.nfiles - 1);
+			if (rover.nfiles > HEIGHT)
+				SCROLL = MIN(SCROLL + RV_JUMP,
+				    rover.nfiles - HEIGHT);
+			update_view();
+		} else if (!strcmp(key, RVK_JUMP_UP)) {
+			if (!rover.nfiles)
+				continue;
+			ESEL = MAX(ESEL - RV_JUMP, 0);
+			SCROLL = MAX(SCROLL - RV_JUMP, 0);
+			update_view();
+		} else if (!strcmp(key, RVK_JUMP_TOP)) {
+			if (!rover.nfiles)
+				continue;
+			ESEL = 0;
+			update_view();
+		} else if (!strcmp(key, RVK_JUMP_BOTTOM)) {
+			if (!rover.nfiles)
+				continue;
+			ESEL = rover.nfiles - 1;
+			update_view();
+		} else if (!strcmp(key, RVK_CD_DOWN)) {
+			if (!rover.nfiles || !S_ISDIR(EMODE(ESEL)))
+				continue;
+			if (chdir(ENAME(ESEL)) == -1) {
+				message(RED, "Cannot access \"%s\".",
+				    ENAME(ESEL));
+				continue;
+			}
+			strcat(CWD, ENAME(ESEL));
+			cd(1);
+		} else if (!strcmp(key, RVK_CD_UP)) {
+			char *dirname, first;
+			if (!strcmp(CWD, "/"))
+				continue;
+			CWD[strlen(CWD) - 1] = '\0';
+			dirname = strrchr(CWD, '/') + 1;
+			first = dirname[0];
+			dirname[0] = '\0';
+			cd(1);
+			dirname[0] = first;
+			dirname[strlen(dirname)] = '/';
+			try_to_sel(dirname);
+			dirname[0] = '\0';
+			if (rover.nfiles > HEIGHT)
+				SCROLL = ESEL - HEIGHT / 2;
+			update_view();
+		} else if (!strcmp(key, RVK_HOME)) {
+			strcpy(CWD, getenv("HOME"));
+			if (CWD[strlen(CWD) - 1] != '/')
+				strcat(CWD, "/");
+			cd(1);
+		} else if (!strcmp(key, RVK_TARGET)) {
+			char *bname, first;
+			int is_dir = S_ISDIR(EMODE(ESEL));
+			ssize_t len = readlink(ENAME(ESEL), BUF1, BUFLEN - 1);
+			if (len == -1)
+				continue;
+			BUF1[len] = '\0';
+			if (access(BUF1, F_OK) == -1) {
+				char *msg;
+				switch (errno) {
+				case EACCES:
+					msg = "Cannot access \"%s\".";
+					break;
+				case ENOENT:
+					msg = "\"%s\" does not exist.";
+					break;
+				default:
+					msg = "Cannot navigate to \"%s\".";
+				}
+				strcpy(BUF2, BUF1); /* message() uses BUF1. */
+				message(RED, msg, BUF2);
+				continue;
+			}
+			realpath(BUF1, CWD);
+			len = strlen(CWD);
+			if (CWD[len - 1] == '/')
+				CWD[len - 1] = '\0';
+			bname = strrchr(CWD, '/') + 1;
+			first = *bname;
+			*bname = '\0';
+			cd(1);
+			*bname = first;
+			if (is_dir)
+				strcat(CWD, "/");
+			try_to_sel(bname);
+			*bname = '\0';
+			update_view();
+		} else if (!strcmp(key, RVK_COPY_PATH)) {
+			clip_path = getenv("CLIP");
+			if (!clip_path)
+				goto copy_path_fail;
+			clip_file = fopen(clip_path, "w");
+			if (!clip_file)
+				goto copy_path_fail;
+			fprintf(clip_file, "%s%s\n", CWD, ENAME(ESEL));
+			fclose(clip_file);
+			goto copy_path_done;
+		copy_path_fail:
+			strcpy(CLIPBOARD, CWD);
+			strcat(CLIPBOARD, ENAME(ESEL));
+		copy_path_done:
+			;
+		} else if (!strcmp(key, RVK_PASTE_PATH)) {
+			clip_path = getenv("CLIP");
+			if (!clip_path)
+				goto paste_path_fail;
+			clip_file = fopen(clip_path, "r");
+			if (!clip_file)
+				goto paste_path_fail;
+			fscanf(clip_file, "%s\n", CLIPBOARD);
+			fclose(clip_file);
+		paste_path_fail:
+			strcpy(BUF1, CLIPBOARD);
+			strcpy(CWD, dirname(BUF1));
+			if (strcmp(CWD, "/"))
+				strcat(CWD, "/");
+			cd(1);
+			strcpy(BUF1, CLIPBOARD);
+			try_to_sel(strstr(CLIPBOARD, basename(BUF1)));
+			update_view();
+		} else if (!strcmp(key, RVK_REFRESH)) {
+			reload();
+		} else if (!strcmp(key, RVK_SHELL)) {
+			program = user_shell;
+			if (program) {
+#ifdef RV_SHELL
+				spawn((char *[]) { RV_SHELL, "-c", program,
+					    NULL});
+#else
+				spawn((char *[]) { program, NULL });
 #endif
-                reload();
-            }
-        } else if (!strcmp(key, RVK_VIEW)) {
-            if (!rover.nfiles || S_ISDIR(EMODE(ESEL))) continue;
-            if (open_with_env(user_pager, ENAME(ESEL)))
-                cd(0);
-        } else if (!strcmp(key, RVK_EDIT)) {
-            if (!rover.nfiles || S_ISDIR(EMODE(ESEL))) continue;
-            if (open_with_env(user_editor, ENAME(ESEL)))
-                cd(0);
-        } else if (!strcmp(key, RVK_OPEN)) {
-            if (!rover.nfiles || S_ISDIR(EMODE(ESEL))) continue;
-            if (open_with_env(user_open, ENAME(ESEL)))
-                cd(0);
-        } else if (!strcmp(key, RVK_SEARCH)) {
-            int oldsel, oldscroll, length;
-            if (!rover.nfiles) continue;
-            oldsel = ESEL;
-            oldscroll = SCROLL;
-            start_line_edit("");
-            update_input(RVP_SEARCH, RED);
-            while ((edit_stat = get_line_edit()) == CONTINUE) {
-                int sel;
-                Color color = RED;
-                length = strlen(INPUT);
-                if (length) {
-                    for (sel = 0; sel < rover.nfiles; sel++)
-                        if (!strncmp(ENAME(sel), INPUT, length))
-                            break;
-                    if (sel < rover.nfiles) {
-                        color = GREEN;
-                        ESEL = sel;
-                        if (rover.nfiles > HEIGHT) {
-                            if (sel < 3)
-                                SCROLL = 0;
-                            else if (sel - 3 > rover.nfiles - HEIGHT)
-                                SCROLL = rover.nfiles - HEIGHT;
-                            else
-                                SCROLL = sel - 3;
-                        }
-                    }
-                } else {
-                    ESEL = oldsel;
-                    SCROLL = oldscroll;
-                }
-                update_view();
-                update_input(RVP_SEARCH, color);
-            }
-            if (edit_stat == CANCEL) {
-                ESEL = oldsel;
-                SCROLL = oldscroll;
-            }
-            clear_message();
-            update_view();
-        } else if (!strcmp(key, RVK_TG_FILES)) {
-            FLAGS ^= SHOW_FILES;
-            reload();
-        } else if (!strcmp(key, RVK_TG_DIRS)) {
-            FLAGS ^= SHOW_DIRS;
-            reload();
-        } else if (!strcmp(key, RVK_TG_HIDDEN)) {
-            FLAGS ^= SHOW_HIDDEN;
-            reload();
-        } else if (!strcmp(key, RVK_NEW_FILE)) {
-            int ok = 0;
-            start_line_edit("");
-            update_input(RVP_NEW_FILE, RED);
-            while ((edit_stat = get_line_edit()) == CONTINUE) {
-                int length = strlen(INPUT);
-                ok = length;
-                for (i = 0; i < rover.nfiles; i++) {
-                    if (
-                        !strncmp(ENAME(i), INPUT, length) &&
-                        (!strcmp(ENAME(i) + length, "") ||
-                         !strcmp(ENAME(i) + length, "/"))
-                    ) {
-                        ok = 0;
-                        break;
-                    }
-                }
-                update_input(RVP_NEW_FILE, ok ? GREEN : RED);
-            }
-            clear_message();
-            if (edit_stat == CONFIRM) {
-                if (ok) {
-                    if (addfile(INPUT) == 0) {
-                        cd(1);
-                        try_to_sel(INPUT);
-                        update_view();
-                    } else
-                        message(RED, "Could not create \"%s\".", INPUT);
-                } else
-                    message(RED, "\"%s\" already exists.", INPUT);
-            }
-        } else if (!strcmp(key, RVK_NEW_DIR)) {
-            int ok = 0;
-            start_line_edit("");
-            update_input(RVP_NEW_DIR, RED);
-            while ((edit_stat = get_line_edit()) == CONTINUE) {
-                int length = strlen(INPUT);
-                ok = length;
-                for (i = 0; i < rover.nfiles; i++) {
-                    if (
-                        !strncmp(ENAME(i), INPUT, length) &&
-                        (!strcmp(ENAME(i) + length, "") ||
-                         !strcmp(ENAME(i) + length, "/"))
-                    ) {
-                        ok = 0;
-                        break;
-                    }
-                }
-                update_input(RVP_NEW_DIR, ok ? GREEN : RED);
-            }
-            clear_message();
-            if (edit_stat == CONFIRM) {
-                if (ok) {
-                    if (adddir(INPUT) == 0) {
-                        cd(1);
-                        strcat(INPUT, "/");
-                        try_to_sel(INPUT);
-                        update_view();
-                    } else
-                        message(RED, "Could not create \"%s/\".", INPUT);
-                } else
-                    message(RED, "\"%s\" already exists.", INPUT);
-            }
-        } else if (!strcmp(key, RVK_RENAME)) {
-            int ok = 0;
-            char *last;
-            int isdir;
-            strcpy(INPUT, ENAME(ESEL));
-            last = INPUT + strlen(INPUT) - 1;
-            if ((isdir = *last == '/'))
-                *last = '\0';
-            start_line_edit(INPUT);
-            update_input(RVP_RENAME, RED);
-            while ((edit_stat = get_line_edit()) == CONTINUE) {
-                int length = strlen(INPUT);
-                ok = length;
-                for (i = 0; i < rover.nfiles; i++)
-                    if (
-                        !strncmp(ENAME(i), INPUT, length) &&
-                        (!strcmp(ENAME(i) + length, "") ||
-                         !strcmp(ENAME(i) + length, "/"))
-                    ) {
-                        ok = 0;
-                        break;
-                    }
-                update_input(RVP_RENAME, ok ? GREEN : RED);
-            }
-            clear_message();
-            if (edit_stat == CONFIRM) {
-                if (isdir)
-                    strcat(INPUT, "/");
-                if (ok) {
-                    if (!rename(ENAME(ESEL), INPUT) && MARKED(ESEL)) {
-                        del_mark(&rover.marks, ENAME(ESEL));
-                        add_mark(&rover.marks, CWD, INPUT);
-                    }
-                    cd(1);
-                    try_to_sel(INPUT);
-                    update_view();
-                } else
-                    message(RED, "\"%s\" already exists.", INPUT);
-            }
-        } else if (!strcmp(key, RVK_TG_EXEC)) {
-            if (!rover.nfiles || S_ISDIR(EMODE(ESEL))) continue;
-            if (S_IXUSR & EMODE(ESEL))
-                EMODE(ESEL) &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
-            else
-                EMODE(ESEL) |=   S_IXUSR | S_IXGRP | S_IXOTH ;
-            if (chmod(ENAME(ESEL), EMODE(ESEL))) {
-                message(RED, "Failed to change mode of \"%s\".", ENAME(ESEL));
-            } else {
-                message(GREEN, "Changed mode of \"%s\".", ENAME(ESEL));
-                update_view();
-            }
-        } else if (!strcmp(key, RVK_DELETE)) {
-            if (rover.nfiles) {
-                message(YELLOW, "Delete \"%s\"? (Y/n)", ENAME(ESEL));
-                if (rover_getch() == 'Y') {
-                    const char *name = ENAME(ESEL);
-                    int ret = ISDIR(ENAME(ESEL)) ? deldir(name) : delfile(name);
-                    reload();
-                    if (ret)
-                        message(RED, "Could not delete \"%s\".", ENAME(ESEL));
-                } else
-                    clear_message();
-            } else
-                  message(RED, "No entry selected for deletion.");
-        } else if (!strcmp(key, RVK_TG_MARK)) {
-            if (MARKED(ESEL))
-                del_mark(&rover.marks, ENAME(ESEL));
-            else
-                add_mark(&rover.marks, CWD, ENAME(ESEL));
-            MARKED(ESEL) = !MARKED(ESEL);
-            ESEL = (ESEL + 1) % rover.nfiles;
-            update_view();
-        } else if (!strcmp(key, RVK_INVMARK)) {
-            for (i = 0; i < rover.nfiles; i++) {
-                if (MARKED(i))
-                    del_mark(&rover.marks, ENAME(i));
-                else
-                    add_mark(&rover.marks, CWD, ENAME(i));
-                MARKED(i) = !MARKED(i);
-            }
-            update_view();
-        } else if (!strcmp(key, RVK_MARKALL)) {
-            for (i = 0; i < rover.nfiles; i++)
-                if (!MARKED(i)) {
-                    add_mark(&rover.marks, CWD, ENAME(i));
-                    MARKED(i) = 1;
-                }
-            update_view();
-        } else if (!strcmp(key, RVK_MARK_DELETE)) {
-            if (rover.marks.nentries) {
-                message(YELLOW, "Delete all marked entries? (Y/n)");
-                if (rover_getch() == 'Y')
-                    process_marked(NULL, delfile, deldir, "Deleting", "Deleted");
-                else
-                    clear_message();
-            } else
-                message(RED, "No entries marked for deletion.");
-        } else if (!strcmp(key, RVK_MARK_COPY)) {
-            if (rover.marks.nentries) {
-                if (strcmp(CWD, rover.marks.dirpath))
-                    process_marked(adddir, cpyfile, NULL, "Copying", "Copied");
-                else
-                    message(RED, "Cannot copy to the same path.");
-            } else
-                message(RED, "No entries marked for copying.");
-        } else if (!strcmp(key, RVK_MARK_MOVE)) {
-            if (rover.marks.nentries) {
-                if (strcmp(CWD, rover.marks.dirpath))
-                    process_marked(adddir, movfile, deldir, "Moving", "Moved");
-                else
-                    message(RED, "Cannot move to the same path.");
-            } else
-                message(RED, "No entries marked for moving.");
-        }
-    }
-    if (rover.nfiles)
-        free_rows(&rover.rows, rover.nfiles);
-    delwin(rover.window);
-    if (save_cwd_file != NULL) {
-        fputs(CWD, save_cwd_file);
-        fclose(save_cwd_file);
-    }
-    if (save_marks_file != NULL) {
-        for (i = 0; i < rover.marks.bulk; i++) {
-            entry = rover.marks.entries[i];
-            if (entry)
-                fprintf(save_marks_file, "%s%s\n", rover.marks.dirpath, entry);
-        }
-        fclose(save_marks_file);
-    }
-    free_marks(&rover.marks);
-    return 0;
+				reload();
+			}
+		} else if (!strcmp(key, RVK_VIEW)) {
+			if (!rover.nfiles || S_ISDIR(EMODE(ESEL)))
+				continue;
+			if (open_with_env(user_pager, ENAME(ESEL)))
+				cd(0);
+		} else if (!strcmp(key, RVK_EDIT)) {
+			if (!rover.nfiles || S_ISDIR(EMODE(ESEL)))
+				continue;
+			if (open_with_env(user_editor, ENAME(ESEL)))
+				cd(0);
+		} else if (!strcmp(key, RVK_OPEN)) {
+			if (!rover.nfiles || S_ISDIR(EMODE(ESEL)))
+				continue;
+			if (open_with_env(user_open, ENAME(ESEL)))
+				cd(0);
+		} else if (!strcmp(key, RVK_SEARCH)) {
+			int oldsel, oldscroll, length;
+			if (!rover.nfiles)
+				continue;
+			oldsel = ESEL;
+			oldscroll = SCROLL;
+			start_line_edit("");
+			update_input(RVP_SEARCH, RED);
+			while ((edit_stat = get_line_edit()) == CONTINUE) {
+				int sel;
+				Color color = RED;
+				length = strlen(INPUT);
+				if (length) {
+					for (sel = 0; sel < rover.nfiles; sel++)
+						if (!strncmp(ENAME(sel), INPUT,
+							length))
+							break;
+					if (sel < rover.nfiles) {
+						color = GREEN;
+						ESEL = sel;
+						if (rover.nfiles > HEIGHT) {
+							if (sel < 3)
+								SCROLL = 0;
+							else if (sel - 3 >
+							    rover.nfiles -
+							    HEIGHT)
+								SCROLL = rover.nfiles -
+									HEIGHT;
+							else
+								SCROLL = sel -
+									3;
+						}
+					}
+				} else {
+					ESEL = oldsel;
+					SCROLL = oldscroll;
+				}
+				update_view();
+				update_input(RVP_SEARCH, color);
+			}
+			if (edit_stat == CANCEL) {
+				ESEL = oldsel;
+				SCROLL = oldscroll;
+			}
+			clear_message();
+			update_view();
+		} else if (!strcmp(key, RVK_TG_FILES)) {
+			FLAGS ^= SHOW_FILES;
+			reload();
+		} else if (!strcmp(key, RVK_TG_DIRS)) {
+			FLAGS ^= SHOW_DIRS;
+			reload();
+		} else if (!strcmp(key, RVK_TG_HIDDEN)) {
+			FLAGS ^= SHOW_HIDDEN;
+			reload();
+		} else if (!strcmp(key, RVK_NEW_FILE)) {
+			int ok = 0;
+			start_line_edit("");
+			update_input(RVP_NEW_FILE, RED);
+			while ((edit_stat = get_line_edit()) == CONTINUE) {
+				int length = strlen(INPUT);
+				ok = length;
+				for (i = 0; i < rover.nfiles; i++) {
+					if (
+						!strncmp(ENAME(i), INPUT, length) &&
+						(!strcmp(ENAME(i) + length, "") ||
+						    !strcmp(ENAME(i) + length, "/"))
+						) {
+						ok = 0;
+						break;
+					}
+				}
+				update_input(RVP_NEW_FILE, ok ? GREEN : RED);
+			}
+			clear_message();
+			if (edit_stat == CONFIRM) {
+				if (ok) {
+					if (addfile(INPUT) == 0) {
+						cd(1);
+						try_to_sel(INPUT);
+						update_view();
+					} else
+						message(RED,
+						    "Could not create \"%s\".",
+						    INPUT);
+				} else
+					message(RED, "\"%s\" already exists.",
+					    INPUT);
+			}
+		} else if (!strcmp(key, RVK_NEW_DIR)) {
+			int ok = 0;
+			start_line_edit("");
+			update_input(RVP_NEW_DIR, RED);
+			while ((edit_stat = get_line_edit()) == CONTINUE) {
+				int length = strlen(INPUT);
+				ok = length;
+				for (i = 0; i < rover.nfiles; i++) {
+					if (
+						!strncmp(ENAME(i), INPUT, length) &&
+						(!strcmp(ENAME(i) + length, "") ||
+						    !strcmp(ENAME(i) + length, "/"))
+						) {
+						ok = 0;
+						break;
+					}
+				}
+				update_input(RVP_NEW_DIR, ok ? GREEN : RED);
+			}
+			clear_message();
+			if (edit_stat == CONFIRM) {
+				if (ok) {
+					if (adddir(INPUT) == 0) {
+						cd(1);
+						strcat(INPUT, "/");
+						try_to_sel(INPUT);
+						update_view();
+					} else
+						message(RED,
+						    "Could not create \"%s/\".",
+						    INPUT);
+				} else
+					message(RED, "\"%s\" already exists.",
+					    INPUT);
+			}
+		} else if (!strcmp(key, RVK_RENAME)) {
+			int ok = 0;
+			char *last;
+			int isdir;
+			strcpy(INPUT, ENAME(ESEL));
+			last = INPUT + strlen(INPUT) - 1;
+			if ((isdir = *last == '/'))
+				*last = '\0';
+			start_line_edit(INPUT);
+			update_input(RVP_RENAME, RED);
+			while ((edit_stat = get_line_edit()) == CONTINUE) {
+				int length = strlen(INPUT);
+				ok = length;
+				for (i = 0; i < rover.nfiles; i++)
+					if (
+						!strncmp(ENAME(i), INPUT, length) &&
+						(!strcmp(ENAME(i) + length, "") ||
+						    !strcmp(ENAME(i) + length, "/"))
+						) {
+						ok = 0;
+						break;
+					}
+				update_input(RVP_RENAME, ok ? GREEN : RED);
+			}
+			clear_message();
+			if (edit_stat == CONFIRM) {
+				if (isdir)
+					strcat(INPUT, "/");
+				if (ok) {
+					if (!rename(ENAME(ESEL), INPUT) &&
+					    MARKED(ESEL)) {
+						del_mark(&rover.marks,
+						    ENAME(ESEL));
+						add_mark(&rover.marks, CWD,
+						    INPUT);
+					}
+					cd(1);
+					try_to_sel(INPUT);
+					update_view();
+				} else
+					message(RED, "\"%s\" already exists.",
+					    INPUT);
+			}
+		} else if (!strcmp(key, RVK_TG_EXEC)) {
+			if (!rover.nfiles || S_ISDIR(EMODE(ESEL)))
+				continue;
+			if (S_IXUSR & EMODE(ESEL))
+				EMODE(ESEL) &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+			else
+				EMODE(ESEL) |= S_IXUSR | S_IXGRP | S_IXOTH;
+			if (chmod(ENAME(ESEL), EMODE(ESEL))) {
+				message(RED,
+				    "Failed to change mode of \"%s\".",
+				    ENAME(ESEL));
+			} else {
+				message(GREEN, "Changed mode of \"%s\".",
+				    ENAME(ESEL));
+				update_view();
+			}
+		} else if (!strcmp(key, RVK_DELETE)) {
+			if (rover.nfiles) {
+				message(YELLOW, "Delete \"%s\"? (Y/n)",
+				    ENAME(ESEL));
+				if (rover_getch() == 'Y') {
+					const char *name = ENAME(ESEL);
+					int ret = ISDIR(ENAME(ESEL)) ?
+						deldir(name) : delfile(name);
+					reload();
+					if (ret)
+						message(RED,
+						    "Could not delete \"%s\".",
+						    ENAME(ESEL));
+				} else
+					clear_message();
+			} else
+				message(RED, "No entry selected for deletion.");
+		} else if (!strcmp(key, RVK_TG_MARK)) {
+			if (MARKED(ESEL))
+				del_mark(&rover.marks, ENAME(ESEL));
+			else
+				add_mark(&rover.marks, CWD, ENAME(ESEL));
+			MARKED(ESEL) = !MARKED(ESEL);
+			ESEL = (ESEL + 1) % rover.nfiles;
+			update_view();
+		} else if (!strcmp(key, RVK_INVMARK)) {
+			for (i = 0; i < rover.nfiles; i++) {
+				if (MARKED(i))
+					del_mark(&rover.marks, ENAME(i));
+				else
+					add_mark(&rover.marks, CWD, ENAME(i));
+				MARKED(i) = !MARKED(i);
+			}
+			update_view();
+		} else if (!strcmp(key, RVK_MARKALL)) {
+			for (i = 0; i < rover.nfiles; i++)
+				if (!MARKED(i)) {
+					add_mark(&rover.marks, CWD, ENAME(i));
+					MARKED(i) = 1;
+				}
+			update_view();
+		} else if (!strcmp(key, RVK_MARK_DELETE)) {
+			if (rover.marks.nentries) {
+				message(YELLOW,
+				    "Delete all marked entries? (Y/n)");
+				if (rover_getch() == 'Y')
+					process_marked(NULL, delfile, deldir,
+					    "Deleting", "Deleted");
+				else
+					clear_message();
+			} else
+				message(RED, "No entries marked for deletion.");
+		} else if (!strcmp(key, RVK_MARK_COPY)) {
+			if (rover.marks.nentries) {
+				if (strcmp(CWD, rover.marks.dirpath))
+					process_marked(adddir, cpyfile, NULL,
+					    "Copying", "Copied");
+				else
+					message(RED,
+					    "Cannot copy to the same path.");
+			} else
+				message(RED, "No entries marked for copying.");
+		} else if (!strcmp(key, RVK_MARK_MOVE)) {
+			if (rover.marks.nentries) {
+				if (strcmp(CWD, rover.marks.dirpath))
+					process_marked(adddir, movfile, deldir,
+					    "Moving", "Moved");
+				else
+					message(RED,
+					    "Cannot move to the same path.");
+			} else
+				message(RED, "No entries marked for moving.");
+		}
+	}
+	if (rover.nfiles)
+		free_rows(&rover.rows, rover.nfiles);
+	delwin(rover.window);
+	if (save_cwd_file != NULL) {
+		fputs(CWD, save_cwd_file);
+		fclose(save_cwd_file);
+	}
+	if (save_marks_file != NULL) {
+		for (i = 0; i < rover.marks.bulk; i++) {
+			entry = rover.marks.entries[i];
+			if (entry)
+				fprintf(save_marks_file, "%s%s\n",
+				    rover.marks.dirpath, entry);
+		}
+		fclose(save_marks_file);
+	}
+	free_marks(&rover.marks);
+	return 0;
 }