Cleaned up the command parsing code a bit to be slightly more correct

and more compact. Now uses if-else-if chain instead of nested switch
statements. This may be very slightly less performant, but probably not
noticeable and much cleaner code.
This commit is contained in:
Bruce Hill 2019-10-13 18:33:46 -07:00
parent e2152a57a3
commit e40feed849
2 changed files with 189 additions and 228 deletions

120
bb.c
View File

@ -59,7 +59,7 @@ void bb_browse(bb_t *bb, const char *path)
while (cmdfile && getdelim(&cmd, &space, '\0', cmdfile) >= 0) {
cmdpos = ftell(cmdfile);
if (!cmd[0]) continue;
process_cmd(bb, cmd);
run_bbcmd(bb, cmd);
if (bb->dirty) {
free(cmd);
fclose(cmdfile);
@ -121,7 +121,7 @@ void bb_browse(bb_t *bb, const char *path)
if (cmdpos != 0)
err("Command file still open");
if (is_simple_bbcmd(binding->script)) {
process_cmd(bb, binding->script);
run_bbcmd(bb, binding->script);
} else {
move_cursor(tty_out, 0, termheight-1);
restore_term(&default_termios);
@ -405,6 +405,16 @@ entry_t* load_entry(bb_t *bb, const char *path, int clear_dots)
return entry;
}
/*
* Return whether a string matches a command
* e.g. matches_cmd("cd:..", "cd") == 1, matches_cmd("q", "quit") == 1
*/
static inline int matches_cmd(const char *str, const char *cmd)
{
while (*str == *cmd && *cmd) ++str, ++cmd;
return *str == '\0' || *str == ':';
}
/*
* Memory allocation failures are unrecoverable in bb, so this wrapper just
* prints an error message and exits if that happens.
@ -565,23 +575,20 @@ void print_bindings(int fd)
* Run a bb internal command (e.g. "+refresh") and return an indicator of what
* needs to happen next.
*/
bb_result_t process_cmd(bb_t *bb, const char *cmd)
bb_result_t run_bbcmd(bb_t *bb, const char *cmd)
{
if (cmd[0] == '+') ++cmd;
else if (strncmp(cmd, "bb +", 4) == 0) cmd = &cmd[4];
const char *value = strchr(cmd, ':');
if (value) ++value;
#define set_bool(target) do { if (!value) { target = !target; } else { target = value[0] == '1'; } } while (0)
switch (cmd[0]) {
case '.': { // +..:, +.:
if (cmd[1] == '.') // +..:
if (matches_cmd(cmd, "..")) { // +..
set_bool(bb->show_dotdot);
else // +.:
populate_files(bb, 1);
} else if (matches_cmd(cmd, ".")) { // +.
set_bool(bb->show_dot);
populate_files(bb, 1);
return BB_OK;
}
case 'b': { // +bind:<keys>:<script>
} else if (matches_cmd(cmd, "bind")) { // +bind:<keys>:<script>
if (!value || !value[0])
return BB_INVALID;
char *value_copy = memcheck(strdup(value));
@ -617,27 +624,14 @@ bb_result_t process_cmd(bb_t *bb, const char *cmd)
}
}
free(value_copy);
return BB_OK;
}
case 'c': { // +cd:, +columns:
switch (cmd[1]) {
case 'd': { // +cd:
} else if (matches_cmd(cmd, "cd")) { // +cd:
if (!value) return BB_INVALID;
if (cd_to(bb, value)) return BB_INVALID;
return BB_OK;
}
case 'o': { // +columns:
} else if (matches_cmd(cmd, "columns")) { // +columns:
if (!value) return BB_INVALID;
strncpy(bb->columns, value, MAX_COLS);
bb->dirty = 1;
return BB_OK;
}
}
return BB_INVALID;
}
case 'd': { // +deselect:, +dotfiles:
switch (cmd[1]) {
case 'e': { // +deselect:
} else if (matches_cmd(cmd, "deselect")) { // +deselect
if (!value) {
while (bb->firstselected)
set_selected(bb, bb->firstselected, 0);
@ -657,25 +651,17 @@ bb_result_t process_cmd(bb_t *bb, const char *cmd)
break;
}
}
return BB_OK;
}
case 'o': { // +dotfiles:
} else if (matches_cmd(cmd, "dotfiles")) { // +dotfiles:
set_bool(bb->show_dotfiles);
populate_files(bb, 1);
return BB_OK;
}
}
}
case 'e': { // +execute:
} else if (matches_cmd(cmd, "execute")) { // +execute:
if (!value || !value[0]) return BB_INVALID;
move_cursor(tty_out, 0, termheight-1);
fputs(T_ON(T_SHOW_CURSOR), tty_out);
restore_term(&default_termios);
run_script(bb, value);
init_term();
return BB_OK;
}
case 'g': { // +goto:
} else if (matches_cmd(cmd, "goto")) { // +goto:
if (!value) return BB_INVALID;
entry_t *e = load_entry(bb, value, 1);
if (!e) return BB_INVALID;
@ -689,13 +675,10 @@ bb_result_t process_cmd(bb_t *bb, const char *cmd)
if (!lastslash) return BB_INVALID;
*lastslash = '\0'; // Split in two
cd_to(bb, pbuf);
if (IS_VIEWED(e)) {
if (IS_VIEWED(e))
set_cursor(bb, e->index);
return BB_OK;
} else try_free_entry(e);
return BB_OK;
}
case 'h': { // +help
else try_free_entry(e);
} else if (matches_cmd(cmd, "help")) { // +help
restore_term(&default_termios);
int fds[2];
pipe(fds);
@ -715,16 +698,12 @@ bb_result_t process_cmd(bb_t *bb, const char *cmd)
init_term();
signal(SIGINT, old_handler);
bb->dirty = 1;
return BB_OK;
}
case 'i': { // +interleave
} else if (matches_cmd(cmd, "interleave")) { // +interleave
set_bool(bb->interleave_dirs);
sort_files(bb);
return BB_OK;
}
case 'k': // +kill
} else if (matches_cmd(cmd, "kill")) { // +kill
cleanup_and_exit(SIGINT);
case 'm': { // +move:
} else if (matches_cmd(cmd, "move")) { // +move:
int oldcur, isdelta, n;
move:
if (!value) return BB_INVALID;
@ -736,22 +715,16 @@ bb_result_t process_cmd(bb_t *bb, const char *cmd)
n = (n * (value[1] == 'n' ? bb->nfiles : termheight)) / 100;
if (isdelta) set_cursor(bb, bb->cursor + n);
else set_cursor(bb, n);
if (cmd[0] == 's') { // +spread:
if (matches_cmd(cmd, "spread")) { // +spread:
int sel = IS_SELECTED(bb->files[oldcur]);
for (int i = bb->cursor; i != oldcur; i += (oldcur > i ? 1 : -1))
set_selected(bb, bb->files[i], sel);
}
return BB_OK;
}
case 'q': // +quit
} else if (matches_cmd(cmd, "quit")) { // +quit
bb->should_quit = 1;
return BB_OK;
case 'r': // +refresh
} else if (matches_cmd(cmd, "refresh")) { // +refresh
populate_files(bb, 1);
return BB_OK;
case 's': // +scroll:, +select:, +sort:, +spread:
switch (cmd[1]) {
case 'c': { // scroll:
} else if (matches_cmd(cmd, "scroll")) { // +scroll:
if (!value) return BB_INVALID;
// TODO: figure out the best version of this
int isdelta = value[0] == '+' || value[0] == '-';
@ -762,41 +735,29 @@ bb_result_t process_cmd(bb_t *bb, const char *cmd)
set_scroll(bb, bb->scroll + n);
else
set_scroll(bb, n);
return BB_OK;
}
case '\0': case 'e': { // +select:
} else if (matches_cmd(cmd, "select")) { // +select:
if (!value && !bb->nfiles) return BB_INVALID;
if (!value) value = bb->files[bb->cursor]->fullname;
entry_t *e = load_entry(bb, value, 1);
if (e) set_selected(bb, e, 1);
return BB_OK;
}
case 'o': // +sort:
} else if (matches_cmd(cmd, "sort")) { // +sort:
if (!value) return BB_INVALID;
set_sort(bb, value);
sort_files(bb);
return BB_OK;
case 'p': // +spread:
} else if (matches_cmd(cmd, "spread")) { // +spread:
goto move;
case 'u': // +suspend
} else if (matches_cmd(cmd, "suspend")) { // +suspend
fputs(T_LEAVE_BBMODE, tty_out);
restore_term(&orig_termios);
raise(SIGTSTP);
init_term();
bb->dirty = 1;
break;
}
case 't': { // +toggle:
} else if (matches_cmd(cmd, "toggle")) { // +toggle
if (!value && !bb->nfiles) return BB_INVALID;
if (!value) value = bb->files[bb->cursor]->fullname;
entry_t *e = load_entry(bb, value, 1);
if (e) set_selected(bb, e, !IS_SELECTED(e));
return BB_OK;
}
default: {
} else {
fputs(T_LEAVE_BBMODE, tty_out);
restore_term(&orig_termios);
const char *msg = "Invalid bb command: ";
@ -806,8 +767,7 @@ bb_result_t process_cmd(bb_t *bb, const char *cmd)
init_term();
return BB_INVALID;
}
}
return BB_INVALID;
return BB_OK;
}
/*

3
bb.h
View File

@ -178,11 +178,12 @@ static int fputs_escaped(FILE *f, const char *str, const char *color);
static void init_term(void);
static int is_simple_bbcmd(const char *s);
static entry_t* load_entry(bb_t *bb, const char *path, int clear_dots);
static inline int matches_cmd(const char *str, const char *cmd);
static void* memcheck(void *p);
static void normalize_path(const char *root, const char *path, char *pbuf, int clear_dots);
static void populate_files(bb_t *bb, int samedir);
static void print_bindings(int fd);
static bb_result_t process_cmd(bb_t *bb, const char *cmd);
static bb_result_t run_bbcmd(bb_t *bb, const char *cmd);
static void render(bb_t *bb);
static void restore_term(const struct termios *term);
static int run_script(bb_t *bb, const char *cmd);