commit - 2254ef432e3c248981cf30cf2cabb26e405d9c68
commit + 3cd6bb9866a46bbe42501cf01f603ffc79524443
blob - 65fbd771773f9a9549c6f17f0ac69ec2ca345a74
blob + 54ce421eafac97861b081f52d164af1f602f6fca
--- rover.c
+++ rover.c
#include "config.h"
+/* String buffers. */
#define ROWSZ 256
-char ROW[ROWSZ];
+static char ROW[ROWSZ];
#define STATUSSZ 256
-char STATUS[STATUSSZ];
+static char STATUS[STATUSSZ];
#define SEARCHSZ 256
-char SEARCH[SEARCHSZ];
+static char SEARCH[SEARCHSZ];
+
+/* Argument buffers for execvp(). */
#define MAXARGS 256
-char *args[MAXARGS];
+static char *ARGS[MAXARGS];
typedef enum {DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, MAGENTA, WHITE} color_t;
+/* Height of listing view. */
#define HEIGHT (LINES-4)
+/* Listing view flags. */
#define SHOW_FILES 0x01u
#define SHOW_DIRS 0x02u
#define SHOW_HIDDEN 0x04u
+/* Information associated to each entry in listing. */
typedef struct {
char *name;
off_t size;
} row_t;
+/* Global state. Some basic info is allocated for ten tabs. */
struct rover_t {
int tab;
int nfiles;
char cwd[10][FILENAME_MAX];
} rover;
-#define FNAME(I) rover.rows[I].name
-#define FSIZE(I) rover.rows[I].size
-#define SCROLL rover.scroll[rover.tab]
-#define FSEL rover.fsel[rover.tab]
-#define FLAGS rover.flags[rover.tab]
-#define CWD rover.cwd[rover.tab]
+/* Macros for accessing global state. */
+#define FNAME(I) rover.rows[I].name
+#define FSIZE(I) rover.rows[I].size
+#define SCROLL rover.scroll[rover.tab]
+#define FSEL rover.fsel[rover.tab]
+#define FLAGS rover.flags[rover.tab]
+#define CWD rover.cwd[rover.tab]
-static int
-rowcmp(const void *a, const void *b)
-{
- int isdir1, isdir2, cmpdir;
- const row_t *r1 = a;
- const row_t *r2 = b;
- isdir1 = strchr(r1->name, '/') != NULL;
- isdir2 = strchr(r2->name, '/') != NULL;
- cmpdir = isdir2 - isdir1;
- return cmpdir ? cmpdir : strcoll(r1->name, r2->name);
-}
-
-void
-free_rows(row_t **rowsp, int nfiles)
-{
- int i;
-
- for (i = 0; i < nfiles; i++)
- free((*rowsp)[i].name);
- free(*rowsp);
- *rowsp = NULL;
-}
-
-int
-ls(char *path, row_t **rowsp, uint8_t flags)
-{
- DIR *dp;
- struct dirent *ep;
- struct stat statbuf;
- row_t *rows;
- int i, n;
-
- if((dp = opendir(path)) == NULL)
- return -1;
- n = -2; /* We don't want the entries "." and "..". */
- while (readdir(dp)) n++;
- rewinddir(dp);
- rows = (row_t *) malloc(n * sizeof(row_t));
- 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;
- /* FIXME: ANSI C doesn't have lstat(). How do we handle symlinks? */
- stat(ep->d_name, &statbuf);
- if (S_ISDIR(statbuf.st_mode)) {
- if (flags & SHOW_DIRS) {
- rows[i].name = (char *) malloc(strlen(ep->d_name) + 2);
- strcpy(rows[i].name, ep->d_name);
- strcat(rows[i].name, "/");
- i++;
- }
- }
- else if (flags & SHOW_FILES) {
- rows[i].name = (char *) malloc(strlen(ep->d_name) + 1);
- strcpy(rows[i].name, ep->d_name);
- rows[i].size = statbuf.st_size;
- i++;
- }
- }
- n = i; /* Ignore unused space in array caused by filters. */
- qsort(rows, n, sizeof(row_t), rowcmp);
- closedir(dp);
- *rowsp = rows;
- return n;
-}
-
+/* Curses clean up. Must be called before exiting browser. */
static void
clean_term()
{
endwin();
}
-void handle_winch(int sig);
+static void handle_winch(int sig);
+/* Curses setup. */
static void
init_term()
{
atexit(clean_term);
}
+/* Update the listing view. */
static void
update_browser()
{
refresh();
}
+/* Comparison used to sort listing entries. */
+static int
+rowcmp(const void *a, const void *b)
+{
+ int isdir1, isdir2, cmpdir;
+ const row_t *r1 = a;
+ const row_t *r2 = b;
+ isdir1 = strchr(r1->name, '/') != NULL;
+ isdir2 = strchr(r2->name, '/') != NULL;
+ cmpdir = isdir2 - isdir1;
+ return cmpdir ? cmpdir : strcoll(r1->name, r2->name);
+}
+
+/* Get all entries for a given path (usually cwd). */
+static int
+ls(char *path, row_t **rowsp, uint8_t flags)
+{
+ DIR *dp;
+ struct dirent *ep;
+ struct stat statbuf;
+ row_t *rows;
+ int i, n;
+
+ if((dp = opendir(path)) == NULL)
+ return -1;
+ n = -2; /* We don't want the entries "." and "..". */
+ while (readdir(dp)) n++;
+ rewinddir(dp);
+ rows = (row_t *) malloc(n * sizeof(row_t));
+ 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;
+ /* FIXME: ANSI C doesn't have lstat(). How do we handle symlinks? */
+ stat(ep->d_name, &statbuf);
+ if (S_ISDIR(statbuf.st_mode)) {
+ if (flags & SHOW_DIRS) {
+ rows[i].name = (char *) malloc(strlen(ep->d_name) + 2);
+ strcpy(rows[i].name, ep->d_name);
+ strcat(rows[i].name, "/");
+ i++;
+ }
+ }
+ else if (flags & SHOW_FILES) {
+ rows[i].name = (char *) malloc(strlen(ep->d_name) + 1);
+ strcpy(rows[i].name, ep->d_name);
+ rows[i].size = statbuf.st_size;
+ i++;
+ }
+ }
+ n = i; /* Ignore unused space in array caused by filters. */
+ qsort(rows, n, sizeof(row_t), rowcmp);
+ closedir(dp);
+ *rowsp = rows;
+ return n;
+}
+
+/* Deallocate entries. */
+static void
+free_rows(row_t **rowsp, int nfiles)
+{
+ int i;
+
+ for (i = 0; i < nfiles; i++)
+ free((*rowsp)[i].name);
+ free(*rowsp);
+ *rowsp = NULL;
+}
+
+/* Change working directory. */
/* NOTE: The caller needs to write the new path to CWD
* *before* calling this function. */
static void
update_browser();
}
+/* SIGWINCH handler; resize application according to new terminal settings. */
static void
+handle_winch(int sig)
+{
+ (void) sig;
+ delwin(rover.window);
+ endwin();
+ refresh();
+ clear();
+ rover.window = subwin(stdscr, LINES - 2, COLS, 1, 0);
+ cd(0);
+}
+
+/* Do a fork-exec to external program ARGS[0] (e.g. $EDITOR). */
+static void
spawn()
{
pid_t pid;
}
else if (pid == 0) {
/* Child process. */
- execvp(args[0], args);
+ execvp(ARGS[0], ARGS);
}
}
/* Interactive getstr(). */
-int
+static int
igetstr(char *buffer, int maxlen)
{
int ch, length;
buffer[length] = '\0';
}
return 1;
-}
-
-void
-handle_winch(int sig)
-{
- (void) sig;
- delwin(rover.window);
- endwin();
- refresh();
- clear();
- rover.window = subwin(stdscr, LINES - 2, COLS, 1, 0);
- cd(0);
}
int
else if (!strcmp(key, RVK_SHELL)) {
program = getenv("SHELL");
if (program) {
- args[0] = program;
- args[1] = NULL;
+ ARGS[0] = program;
+ ARGS[1] = NULL;
spawn();
}
}
continue;
program = getenv("PAGER");
if (program) {
- args[0] = program;
- args[1] = FNAME(FSEL);
- args[2] = NULL;
+ ARGS[0] = program;
+ ARGS[1] = FNAME(FSEL);
+ ARGS[2] = NULL;
spawn();
}
}
continue;
program = getenv("EDITOR");
if (program) {
- args[0] = program;
- args[1] = FNAME(FSEL);
- args[2] = NULL;
+ ARGS[0] = program;
+ ARGS[1] = FNAME(FSEL);
+ ARGS[2] = NULL;
spawn();
}
}