Cleanup, added FOREACH() macro, fixed some bugs with key bindings.

This commit is contained in:
Bruce Hill 2021-07-29 00:23:32 -07:00
parent 783f127199
commit 5308519842
3 changed files with 74 additions and 66 deletions

134
bb.c
View File

@ -32,7 +32,7 @@
#define BB_NAME "bb" #define BB_NAME "bb"
#endif #endif
#define BB_VERSION "0.30.0" #define BB_VERSION "0.31.0"
#define MAX_BINDINGS 1024 #define MAX_BINDINGS 1024
#define SCROLLOFF MIN(5, (winsize.ws_row-4)/2) #define SCROLLOFF MIN(5, (winsize.ws_row-4)/2)
#define ONSCREEN (winsize.ws_row - 3) #define ONSCREEN (winsize.ws_row - 3)
@ -86,9 +86,16 @@ static struct winsize winsize = {0};
static char cmdfilename[PATH_MAX] = {0}; static char cmdfilename[PATH_MAX] = {0};
static bb_t *current_bb = NULL; static bb_t *current_bb = NULL;
static char err_tmpfilename[PATH_MAX] = {0}; // Redirect stderr/stdout to these files during execution, and dump them on exit
int stderr_dup_fd = -1, err_tmp_fd = -1; typedef struct {
FILE *err_file = NULL; int orig_fd, dup_fd, tmp_fd;
const char *name;
char filename[PATH_MAX];
} outbuf_t;
outbuf_t output_buffers[] = {
{.name="stdout", .orig_fd=STDOUT_FILENO, .dup_fd=-1, .tmp_fd=-1},
{.name="stderr", .orig_fd=STDERR_FILENO, .dup_fd=-1, .tmp_fd=-1},
};
// //
// Use bb to browse the filesystem. // Use bb to browse the filesystem.
@ -194,7 +201,7 @@ static void cleanup_and_raise(int sig)
} }
// //
// Reset the screen and delete the cmdfile // Reset the screen, delete the cmdfile, and print the stdout/stderr buffers
// //
static void cleanup(void) static void cleanup(void)
{ {
@ -207,16 +214,17 @@ static void cleanup(void)
fflush(tty_out); fflush(tty_out);
tcsetattr(fileno(tty_out), TCSANOW, &orig_termios); tcsetattr(fileno(tty_out), TCSANOW, &orig_termios);
} }
if (err_tmp_fd != -1) { FOREACH(outbuf_t*, ob, output_buffers) {
fflush(stderr); if (ob->tmp_fd == -1) continue;
dup2(stderr_dup_fd, STDERR_FILENO); // Put stderr back to normal fflush(ob->orig_fd == STDOUT_FILENO ? stdout : stderr);
dup2(ob->dup_fd, ob->orig_fd);
lseek(ob->tmp_fd, 0, SEEK_SET);
char buf[256]; char buf[256];
lseek(err_tmp_fd, 0, SEEK_SET); for (ssize_t len; (len = read(ob->tmp_fd, buf, LEN(buf))) > 0; )
for (ssize_t len; (len = read(err_tmp_fd, buf, sizeof(buf))) > 0; ) write(ob->orig_fd, buf, len);
write(STDERR_FILENO, buf, len); close(ob->tmp_fd);
close(err_tmp_fd); ob->tmp_fd = ob->dup_fd = -1;
err_tmp_fd = stderr_dup_fd = -1; unlink(ob->filename);
unlink(err_tmpfilename);
} }
} }
@ -314,9 +322,9 @@ static void handle_next_key_binding(bb_t *bb)
} while (key == -1); } while (key == -1);
binding = NULL; binding = NULL;
for (size_t i = 0; bindings[i].script && i < sizeof(bindings)/sizeof(bindings[0]); i++) { FOREACH(binding_t*, b, bindings) {
if (key == bindings[i].key) { if (key == b->key) {
binding = &bindings[i]; binding = b;
break; break;
} }
} }
@ -614,30 +622,24 @@ static int populate_files(bb_t *bb, const char *path)
// //
static void print_bindings(int fd) static void print_bindings(int fd)
{ {
char buf[1000], buf2[1024]; FOREACH(binding_t*, b, bindings) {
for (size_t i = 0; bindings[i].script && i < sizeof(bindings)/sizeof(bindings[0]); i++) { if (!b->description) break;
if (bindings[i].key == -1) { if (b->key == -1) {
const char *label = bindings[i].description; const char *label = b->description;
sprintf(buf, "\n\033[33;1;4m\033[%dG%s\033[0m\n", (winsize.ws_col-(int)strlen(label))/2, label); dprintf(fd, "\n\033[33;1;4m\033[%dG%s\033[0m\n", (winsize.ws_col-(int)strlen(label))/2, label);
write(fd, buf, strlen(buf));
continue; continue;
} }
size_t shared = 0; char buf[1000];
char *p = buf; char *p = buf;
for (size_t j = i; bindings[j].script && streq(bindings[j].description, bindings[i].description); j++) { for (binding_t *next = b; next < &bindings[LEN(bindings)] && next->script && streq(b->description, next->description); next++) {
if (j > i) p = stpcpy(p, ", "); if (next > b) p = stpcpy(p, ", ");
++shared; p = bkeyname(next->key, p);
int key = bindings[j].key; b = next;
p = bkeyname(key, p);
} }
*p = '\0'; *p = '\0';
sprintf(buf2, "\033[1m\033[%dG%s\033[0m", winsize.ws_col/2 - 1 - (int)strlen(buf), buf); dprintf(fd, "\033[1m\033[%dG%s\033[0m", winsize.ws_col/2 - 1 - (int)strlen(buf), buf);
write(fd, buf2, strlen(buf2)); dprintf(fd, "\033[1m\033[%dG\033[34m%s\033[0m", winsize.ws_col/2 + 1, b->description);
sprintf(buf2, "\033[1m\033[%dG\033[34m%s\033[0m", winsize.ws_col/2 + 1,
bindings[i].description);
write(fd, buf2, strlen(buf2));
write(fd, "\033[0m\n", strlen("\033[0m\n")); write(fd, "\033[0m\n", strlen("\033[0m\n"));
i += shared - 1;
} }
write(fd, "\n", 1); write(fd, "\n", 1);
} }
@ -671,28 +673,31 @@ static void run_bbcmd(bb_t *bb, const char *cmd)
else script = trim(script); else script = trim(script);
} else description = script; } else description = script;
for (char *key; (key = strsep(&keys, ",")); ) { for (char *key; (key = strsep(&keys, ",")); ) {
if (streq(key, "Section")) continue; int keyval;
int keyval = bkeywithname(key); if (streq(key, "Section")) {
if (keyval == -1) continue; keyval = -1;
for (size_t i = 0; i < sizeof(bindings)/sizeof(bindings[0]); i++) { } else {
if (bindings[i].script && bindings[i].key != keyval) keyval = bkeywithname(key);
continue; if (keyval == -1) continue;
char *script2; // Delete existing bindings for this key (if any):
if (is_simple_bbcmd(script)) { FOREACH(binding_t*, b, bindings) {
script2 = check_strdup(script); if (b->key == keyval) {
} else { delete((char**)&b->description);
const char *prefix = "set -e\n"; delete((char**)&b->script);
script2 = new_bytes(strlen(prefix) + strlen(script) + 1); memmove(b, b+1, (size_t)(&bindings[LEN(bindings)] - (b+1)));
sprintf(script2, "%s%s", prefix, script); memset(&bindings[LEN(bindings)-1], 0, sizeof(binding_t));
}
} }
binding_t binding = {keyval, script2, check_strdup(description)}; }
if (bindings[i].key == keyval) { // Append binding:
delete((char**)&bindings[i].description); FOREACH(binding_t*, b, bindings) {
delete((char**)&bindings[i].script); if (b->script) continue;
for (; i + 1 < sizeof(bindings)/sizeof(bindings[0]) && bindings[i+1].key; i++) b->key = keyval;
bindings[i] = bindings[i+1]; if (is_simple_bbcmd(script))
} b->script = check_strdup(script);
bindings[i] = binding; else
nonnegative(asprintf((char**)&b->script, "set -e\n%s", script), "Could not copy script");
b->description = check_strdup(description);
break; break;
} }
} }
@ -767,7 +772,7 @@ static void run_bbcmd(bb_t *bb, const char *cmd)
else try_free_entry(e); else try_free_entry(e);
} else if (matches_cmd(cmd, "help")) { // +help } else if (matches_cmd(cmd, "help")) { // +help
char filename[PATH_MAX]; char filename[PATH_MAX];
sprintf(filename, "%s/bbhelp.XXXXXX", getenv("TMPDIR")); sprintf(filename, "%s/"BB_NAME".help.XXXXXX", getenv("TMPDIR"));
int fd = nonnegative(mkstemp(filename), "Couldn't create temporary help file at %s", filename); int fd = nonnegative(mkstemp(filename), "Couldn't create temporary help file at %s", filename);
print_bindings(fd); print_bindings(fd);
close(fd); close(fd);
@ -1133,7 +1138,7 @@ int main(int argc, char *argv[])
// Set up environment variables // Set up environment variables
// Default values // Default values
setenv("TMPDIR", "/tmp", 0); setenv("TMPDIR", "/tmp", 0);
sprintf(cmdfilename, "%s/"BB_NAME".XXXXXX", getenv("TMPDIR")); sprintf(cmdfilename, "%s/"BB_NAME".cmd.XXXXXX", getenv("TMPDIR"));
int cmdfd = nonnegative( int cmdfd = nonnegative(
mkostemp(cmdfilename, O_APPEND), mkostemp(cmdfilename, O_APPEND),
"Couldn't create "BB_NAME" command file: '%s'", cmdfilename); "Couldn't create "BB_NAME" command file: '%s'", cmdfilename);
@ -1179,10 +1184,12 @@ int main(int argc, char *argv[])
atexit(cleanup); atexit(cleanup);
sprintf(err_tmpfilename, "%s/"BB_NAME".err.XXXXXX", getenv("TMPDIR")); FOREACH(outbuf_t*, ob, output_buffers) {
err_tmp_fd = nonnegative(mkostemp(err_tmpfilename, O_RDWR), "Couldn't create error file"); sprintf(ob->filename, "%s/"BB_NAME".%s.XXXXXX", getenv("TMPDIR"), ob->name);
stderr_dup_fd = nonnegative(dup(STDERR_FILENO)); ob->tmp_fd = nonnegative(mkostemp(ob->filename, O_RDWR), "Couldn't create error file");
nonnegative(dup2(err_tmp_fd, STDERR_FILENO), "Couldn't redirect error output"); ob->dup_fd = nonnegative(dup(ob->orig_fd));
nonnegative(dup2(ob->tmp_fd, ob->orig_fd), "Couldn't redirect error output");
}
tty_in = nonnull(fopen("/dev/tty", "r")); tty_in = nonnull(fopen("/dev/tty", "r"));
tty_out = nonnull(fopen("/dev/tty", "w")); tty_out = nonnull(fopen("/dev/tty", "w"));
@ -1194,7 +1201,7 @@ int main(int argc, char *argv[])
int signals[] = {SIGTERM, SIGINT, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGSEGV, SIGTSTP}; int signals[] = {SIGTERM, SIGINT, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGSEGV, SIGTSTP};
struct sigaction sa = {.sa_handler = &cleanup_and_raise, .sa_flags = (int)(SA_NODEFER | SA_RESETHAND)}; struct sigaction sa = {.sa_handler = &cleanup_and_raise, .sa_flags = (int)(SA_NODEFER | SA_RESETHAND)};
for (size_t i = 0; i < sizeof(signals)/sizeof(signals[0]); i++) for (size_t i = 0; i < LEN(signals); i++)
sigaction(signals[i], &sa, NULL); sigaction(signals[i], &sa, NULL);
bb_t bb = { bb_t bb = {
@ -1206,6 +1213,7 @@ int main(int argc, char *argv[])
set_globs(&bb, "*"); set_globs(&bb, "*");
init_term(); init_term();
bb_browse(&bb, argc, argv); bb_browse(&bb, argc, argv);
cleanup(); // Optional, but this allows us to write directly to stdout instead of the buffer
if (bb.selected && print_selection) { if (bb.selected && print_selection) {
for (entry_t *e = bb.selected; e; e = e->selected.next) { for (entry_t *e = bb.selected; e; e = e->selected.next) {

View File

@ -318,6 +318,3 @@ key="$(bbask -1 "Press key to bind...")"
echo echo
script="$(bbask "Bind script: ")" script="$(bbask "Bind script: ")"
bbcmd bind:"$key":"{ $script; } || bbpause" bbcmd bind:"$key":"{ $script; } || bbpause"
## Section: User Bindings

View File

@ -53,6 +53,9 @@
((node)->name).next = NULL; \ ((node)->name).next = NULL; \
} while (0) } while (0)
#define LEN(a) (sizeof(a)/sizeof(a[0]))
#define FOREACH(type, var, array) for (type var = array; (var) < &(array)[LEN(array)]; var++)
#define S1(x) #x #define S1(x) #x
#define S2(x) S1(x) #define S2(x) S1(x)
#define __LOCATION__ __FILE__ ":" S2(__LINE__) #define __LOCATION__ __FILE__ ":" S2(__LINE__)