aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bb.c147
-rw-r--r--config.def.h6
2 files changed, 85 insertions, 68 deletions
diff --git a/bb.c b/bb.c
index 5d863f3..a33ba86 100644
--- a/bb.c
+++ b/bb.c
@@ -30,38 +30,34 @@
#define PATH_MAX 4096
#endif
+#define MAX_COLS 12
+#define MAX_SORT (2*MAX_COLS)
#define MAX(a,b) ((a) < (b) ? (b) : (a))
#define MIN(a,b) ((a) > (b) ? (b) : (a))
#define IS_SELECTED(p) (((p)->atme) != NULL)
#define LOWERCASE(c) ('A' <= (c) && (c) <= 'Z' ? ((c) + 'a' - 'A') : (c))
-static const char *T_ENTER_BBMODE = T_OFF(T_SHOW_CURSOR) T_ON(T_MOUSE_XY ";" T_MOUSE_CELL ";" T_MOUSE_SGR);
-static const char *T_LEAVE_BBMODE = T_OFF(T_MOUSE_XY ";" T_MOUSE_CELL ";" T_MOUSE_SGR ";" T_ALT_SCREEN);
-static const char *T_LEAVE_BBMODE_PARTIAL = T_OFF(T_MOUSE_XY ";" T_MOUSE_CELL ";" T_MOUSE_SGR);
-
#define err(...) do { \
- close_term(); \
- fputs(T_OFF(T_ALT_SCREEN), stdout); \
- fflush(stdout); \
+ cleanup(); \
fprintf(stderr, __VA_ARGS__); \
if (errno) fprintf(stderr, "\n%s", strerror(errno)); \
fprintf(stderr, "\n"); \
- cleanup_and_exit(1); \
+ exit(EXIT_FAILURE); \
} while (0)
// Types
typedef enum {
- SORT_NONE = 0,
- SORT_DIR = '/',
- SORT_NAME = 'n',
- SORT_SIZE = 's',
- SORT_PERM = 'p',
- SORT_MTIME = 'm',
- SORT_CTIME = 'c',
- SORT_ATIME = 'a',
- SORT_RANDOM = 'r',
- SORT_SELECTED = '*',
-} sortmethod_t;
+ COL_NONE = 0,
+ COL_DIR = '/',
+ COL_NAME = 'n',
+ COL_SIZE = 's',
+ COL_PERM = 'p',
+ COL_MTIME = 'm',
+ COL_CTIME = 'c',
+ COL_ATIME = 'a',
+ COL_RANDOM = 'r',
+ COL_SELECTED = '*',
+} column_t;
/* entry_t uses intrusive linked lists. This means entries can only belong to
* one list at a time, in this case the list of selected entries. 'atme' is an
@@ -81,9 +77,6 @@ typedef struct entry_s {
char fullname[1]; // Must be last
} entry_t;
-#define MAX_COLS 12
-#define MAX_SORT (2*MAX_COLS)
-
typedef struct {
char sort[MAX_SORT+1];
char columns[MAX_COLS+1];
@@ -111,6 +104,7 @@ static void update_term_size(int sig);
static void init_term(void);
static void close_term(void);
static void cleanup_and_exit(int sig);
+static void cleanup(void);
static void* memcheck(void *p);
static int run_cmd_on_selection(bb_t *bb, const char *cmd);
static int fputs_escaped(FILE *f, const char *str, const char *color);
@@ -135,6 +129,11 @@ static void print_bindings(void);
extern binding_t bindings[];
extern const char *startupcmds[];
+// Constants
+static const char *T_ENTER_BBMODE = T_OFF(T_SHOW_CURSOR) T_ON(T_MOUSE_XY ";" T_MOUSE_CELL ";" T_MOUSE_SGR);
+static const char *T_LEAVE_BBMODE = T_OFF(T_MOUSE_XY ";" T_MOUSE_CELL ";" T_MOUSE_SGR ";" T_ALT_SCREEN);
+static const char *T_LEAVE_BBMODE_PARTIAL = T_OFF(T_MOUSE_XY ";" T_MOUSE_CELL ";" T_MOUSE_SGR);
+
// Global variables
static struct termios orig_termios, bb_termios;
static FILE *tty_out = NULL, *tty_in = NULL;
@@ -212,10 +211,27 @@ void close_term(void)
*/
void cleanup_and_exit(int sig)
{
- (void)sig;
+ static volatile sig_atomic_t error_in_progress = 0;
+ if (error_in_progress)
+ raise(sig);
+ error_in_progress = 1;
+ cleanup();
+ signal(sig, SIG_DFL);
+ raise(sig);
+}
+
+/*
+ * Close the terminal, reset the screen, and delete the cmdfile
+ */
+void cleanup(void)
+{
+ if (cmdfilename) {
+ unlink(cmdfilename);
+ cmdfilename = NULL;
+ }
close_term();
- unlink(cmdfilename);
- exit(EXIT_FAILURE);
+ fputs(T_OFF(T_ALT_SCREEN), stdout);
+ fflush(stdout);
}
/*
@@ -361,15 +377,15 @@ void render(bb_t *bb, int lazy)
for (int col = 0; bb->options.columns[col]; col++) {
const char *title = NULL;
switch (bb->options.columns[col]) {
- case '*': title = "*"; break;
- case '/': title = "/"; break;
- case 'r': title = "Random"; break;
- case 'n': title = "Name"; break;
- case 's': title = "Size"; break;
- case 'p': title = "Permissions"; break;
- case 'm': title = "Modified"; break;
- case 'a': title = "Accessed"; break;
- case 'c': title = "Created"; break;
+ case COL_SELECTED: title = "*"; break;
+ case COL_DIR: title = "/"; break;
+ case COL_RANDOM: title = "Random"; break;
+ case COL_NAME: title = "Name"; break;
+ case COL_SIZE: title = "Size"; break;
+ case COL_PERM: title = "Permissions"; break;
+ case COL_MTIME: title = "Modified"; break;
+ case COL_ATIME: title = "Accessed"; break;
+ case COL_CTIME: title = "Created"; break;
default: title = ""; break;
}
move_cursor(tty_out, x, 1);
@@ -434,13 +450,13 @@ void render(bb_t *bb, int lazy)
}
int k = bb->options.aligns[col] == 'c' ? 1 : (bb->options.aligns[col] == 'r' ? 2 : 0);
switch (bb->options.columns[col]) {
- case '*':
+ case COL_SELECTED:
move_cursor(tty_out, x + MAX(0, (k*(bb->options.colwidths[col] - colselw))/2), y);
fputs(IS_SELECTED(entry) ? SELECTED_INDICATOR : NOT_SELECTED_INDICATOR, tty_out);
fputs(i == bb->cursor ? CURSOR_COLOR : "\033[0m", tty_out);
break;
- case '/':
+ case COL_DIR:
move_cursor(tty_out, x + MAX(0, (k*(bb->options.colwidths[col] - coldirw))/2), y);
if (S_ISDIR(S_ISLNK(entry->info.st_mode) ? entry->linkedmode : entry->info.st_mode))
fputs("/", tty_out);
@@ -448,13 +464,13 @@ void render(bb_t *bb, int lazy)
fputs(" ", tty_out);
break;
- case 'r':
+ case COL_RANDOM:
move_cursor(tty_out, x + MAX(0, (k*(bb->options.colwidths[col] - colrandw))/2), y);
fprintf(tty_out, "\033[48;5;%dm \033[0m%s", 232 + (entry->shufflepos / (RAND_MAX / (255-232))),
i == bb->cursor ? CURSOR_COLOR : "\033[0m");
break;
- case 's': {
+ case COL_SIZE: {
int j = 0;
const char* units = "BKMGTPEZY";
double bytes = (double)entry->info.st_size;
@@ -467,30 +483,30 @@ void render(bb_t *bb, int lazy)
break;
}
- case 'm':
+ case COL_MTIME:
move_cursor(tty_out, x + MAX(0, (k*(bb->options.colwidths[col] - coldatew))/2), y);
strftime(buf, sizeof(buf), "%l:%M%p %b %e %Y", localtime(&(entry->info.st_mtime)));
fputs(buf, tty_out);
break;
- case 'c':
+ case COL_CTIME:
move_cursor(tty_out, x + MAX(0, (k*(bb->options.colwidths[col] - coldatew))/2), y);
strftime(buf, sizeof(buf), "%l:%M%p %b %e %Y", localtime(&(entry->info.st_ctime)));
fputs(buf, tty_out);
break;
- case 'a':
+ case COL_ATIME:
move_cursor(tty_out, x + MAX(0, (k*(bb->options.colwidths[col] - coldatew))/2), y);
strftime(buf, sizeof(buf), "%l:%M%p %b %e %Y", localtime(&(entry->info.st_atime)));
fputs(buf, tty_out);
break;
- case 'p':
+ case COL_PERM:
move_cursor(tty_out, x + MAX(0, (k*(bb->options.colwidths[col] - colpermw))/2), y);
fprintf(tty_out, " %03o", entry->info.st_mode & 0777);
break;
- case 'n': {
+ case COL_NAME: {
char color[128];
strcpy(color, color_of(entry->info.st_mode));
if (i == bb->cursor) strcat(color, CURSOR_COLOR);
@@ -558,16 +574,16 @@ int compare_files(void *v, const void *v1, const void *v2)
continue;
}
switch (*sort) {
- case SORT_DIR: {
+ case COL_DIR: {
int d1 = S_ISDIR(f1->info.st_mode) || (S_ISLNK(f1->info.st_mode) && S_ISDIR(f1->linkedmode));
int d2 = S_ISDIR(f2->info.st_mode) || (S_ISLNK(f2->info.st_mode) && S_ISDIR(f2->linkedmode));
diff = compare(d1, d2);
break;
}
- case SORT_SELECTED:
+ case COL_SELECTED:
diff = compare(IS_SELECTED(f1), IS_SELECTED(f2));
break;
- case SORT_NAME: {
+ case COL_NAME: {
/* This sorting method is not identical to strverscmp(). Notably, bb's sort
* will order: [0, 1, 9, 00, 01, 09, 10, 000, 010] instead of strverscmp()'s
* order: [000, 00, 01, 010, 09, 0, 1, 9, 10]. I believe bb's sort is consistent
@@ -601,22 +617,22 @@ int compare_files(void *v, const void *v1, const void *v2)
diff = -compare(LOWERCASE(*n1), LOWERCASE(*n2));
break;
}
- case SORT_PERM:
+ case COL_PERM:
diff = compare((f1->info.st_mode & 0x3FF), (f2->info.st_mode & 0x3FF));
break;
- case SORT_SIZE:
+ case COL_SIZE:
diff = compare(f1->info.st_size, f2->info.st_size);
break;
- case SORT_MTIME:
+ case COL_MTIME:
diff = compare_time(f1->info.st_mtimespec, f2->info.st_mtimespec);
break;
- case SORT_CTIME:
+ case COL_CTIME:
diff = compare_time(f1->info.st_ctimespec, f2->info.st_ctimespec);
break;
- case SORT_ATIME:
+ case COL_ATIME:
diff = compare_time(f1->info.st_atimespec, f2->info.st_atimespec);
break;
- case SORT_RANDOM:
+ case COL_RANDOM:
diff = f1->shufflepos - f2->shufflepos;
break;
}
@@ -878,7 +894,7 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd)
{
char *value = strchr(cmd, ':');
if (value) ++value;
-#define set_bool(target) do { if (!value || value[0] == '~') { target = !target; } else { target = value[0] == '1'; } } while (0)
+#define set_bool(target) do { if (!value) { target = !target; } else { target = value[0] == '1'; } } while (0)
switch (cmd[0]) {
case '.': { // +..:, +.:
if (cmd[1] == '.') // +..:
@@ -933,13 +949,14 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd)
for (int i = 0; i < value[i] && i < MAX_COLS; i++) {
int *colw = &bb->options.colwidths[i];
switch (value[i]) {
- case 'c': case 'm': case 'a': *colw = coldatew; break;
- case 's': *colw = colsizew; break;
- case 'p': *colw = colpermw; break;
- case 'n': *colw = colnamew; break;
- case '*': *colw = colselw; break;
- case 'r': *colw = colrandw; break;
- case '/': *colw = coldirw; break;
+ case COL_CTIME: case COL_MTIME: case COL_ATIME:
+ *colw = coldatew; break;
+ case COL_SIZE: *colw = colsizew; break;
+ case COL_PERM: *colw = colpermw; break;
+ case COL_NAME: *colw = colnamew; break;
+ case COL_SELECTED: *colw = colselw; break;
+ case COL_RANDOM: *colw = colrandw; break;
+ case COL_DIR: *colw = coldirw; break;
}
}
return BB_REFRESH;
@@ -1206,7 +1223,7 @@ void bb_browse(bb_t *bb, const char *path)
} else if (2 <= mouse_y && mouse_y <= termheight - 2) {
int clicked = bb->scroll + (mouse_y - 2);
if (clicked > bb->nfiles - 1) goto next_input;
- if (column[1] == SORT_SELECTED) {
+ if (column[1] == COL_SELECTED) {
toggle_file(bb, bb->files[clicked]);
lazy = 0;
goto redraw;
@@ -1223,7 +1240,6 @@ void bb_browse(bb_t *bb, const char *path)
case KEY_CTRL_C:
cleanup_and_exit(SIGINT);
- goto quit; // Unreachable
case KEY_CTRL_Z:
fputs(T_OFF(T_ALT_SCREEN), tty_out);
@@ -1297,7 +1313,7 @@ void bb_browse(bb_t *bb, const char *path)
quit:
populate_files(bb, NULL);
fputs(T_LEAVE_BBMODE, tty_out);
- close_term();
+ cleanup();
}
/*
@@ -1442,6 +1458,7 @@ int main(int argc, char *argv[])
setenv("EDITOR", "nano", 0);
setenv("PAGER", "less", 0);
+ atexit(cleanup);
signal(SIGTERM, cleanup_and_exit);
signal(SIGINT, cleanup_and_exit);
signal(SIGXCPU, cleanup_and_exit);
@@ -1454,8 +1471,8 @@ int main(int argc, char *argv[])
if (!real || chdir(real)) err("Not a valid path: %s\n", initial_path);
bb_t *bb = memcheck(calloc(1, sizeof(bb_t)));
- bb->options.columns[0] = 'n';
- bb->options.sort[0] = 'n';
+ bb->options.columns[0] = COL_NAME;
+ strcpy(bb->options.sort, "+/+n");
bb_browse(bb, real);
free(real);
diff --git a/config.def.h b/config.def.h
index 698ddba..d6a48e1 100644
--- a/config.def.h
+++ b/config.def.h
@@ -21,13 +21,13 @@
In order to modify bb's internal state, you can call `bb +cmd`, where "cmd"
is one of the following commands (or a unique prefix of one):
- .:(0|1|~) Whether to show "." in each directory
- ..:(0|1|~) Whether to show ".." in each directory
+ .:[01] Whether to show "." in each directory
+ ..:[01] Whether to show ".." in each directory
align:<col-aligns> Direction of column text alignment ('r' for right, 'c' for center, and 'l' for left)
cd:<path> Navigate to <path>
columns:<columns> Change which columns are visible, and in what order
deselect:<filename> Deselect <filename>
- dotfiles:(0|1|~) Whether dotfiles are visible
+ dotfiles:[01] Whether dotfiles are visible
goto:<filename> Move the cursor to <filename> (changing directory if needed)
jump:<key> Jump to the mark associated with <key>
mark:<key>[=<path>] Associate <key> with <path> (or current dir, if blank)