From f539538582c3a5dba7ce5ca344115beea52f054d Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 31 May 2019 12:47:35 -0700 Subject: [PATCH] Cleaned up a lot of the cd logic, making path names better-standardized, but still keeping symlinks, and ensuring bb->path has a slash at the end. Also cleaned up some empty directory errors. --- bb.c | 130 +++++++++++++++++++++++++++++---------------------- config.def.h | 2 +- 2 files changed, 75 insertions(+), 57 deletions(-) diff --git a/bb.c b/bb.c index ba12b61..d2fb92e 100644 --- a/bb.c +++ b/bb.c @@ -144,6 +144,7 @@ static void set_scroll(bb_t *bb, int i); static entry_t* load_entry(bb_t *bb, const char *path); static void remove_entry(entry_t *e); static void sort_files(bb_t *bb); +static int cd_to(bb_t *bb, const char *path); static void populate_files(bb_t *bb, const char *path); static bb_result_t execute_cmd(bb_t *bb, const char *cmd); static void bb_browse(bb_t *bb, const char *path); @@ -288,7 +289,7 @@ int run_cmd_on_selection(bb_t *bb, const char *cmd) args[i++] = "-c"; args[i++] = (char*)cmd; args[i++] = "--"; // ensure files like "-i" are not interpreted as flags for sh - entry_t *first = bb->firstselected ? bb->firstselected : bb->files[bb->cursor]; + entry_t *first = bb->firstselected ? bb->firstselected : (bb->nfiles ? bb->files[bb->cursor] : NULL); for (entry_t *e = first; e; e = e->selected.next) { if (i >= space) args = memcheck(realloc(args, (space += 100)*sizeof(char*))); @@ -297,7 +298,7 @@ int run_cmd_on_selection(bb_t *bb, const char *cmd) args[i] = NULL; setenv("BBSELECTED", bb->firstselected ? "1" : "", 1); - setenv("BBCURSOR", bb->files[bb->cursor]->fullname, 1); + setenv("BBCURSOR", bb->nfiles ? bb->files[bb->cursor]->fullname : "", 1); execvp("sh", args); err("Failed to execute command: '%s'", cmd); @@ -756,9 +757,15 @@ entry_t* load_entry(bb_t *bb, const char *path) struct stat linkedstat, filestat; if (lstat(path, &filestat) == -1) return NULL; char path2[PATH_MAX]; - if (path[0] != '/') { + if (path[0] == '~' && (path[1] == '\0' || path[1] == '/')) { + char *home; + if (!(home = getenv("HOME"))) + return NULL; + strcpy(path2, home); + strcat(path2, path+1); + path = path2; + } else if (path[0] != '/') { strcpy(path2, bb->path); - strcat(path2, "/"); strcat(path2, path); path = path2; } @@ -816,12 +823,52 @@ void sort_files(bb_t *bb) #else qsort_r(bb->files, (size_t)bb->nfiles, sizeof(entry_t*), compare_files, bb); #endif - for (int i = 0; i < bb->nfiles; i++) { + for (int i = 0; i < bb->nfiles; i++) bb->files[i]->index = i; - } bb->dirty = 1; } +int cd_to(bb_t *bb, const char *path) +{ + char pbuf[PATH_MAX]; + if (path[0] == '~' && (path[1] == '\0' || path[1] == '/')) { + char *home; + if (!(home = getenv("HOME"))) + return BB_INVALID; + strcpy(pbuf, home); + strcat(pbuf, path+1); + } else if (path[0] == '/') { + strcpy(pbuf, path); + } else { + strcpy(pbuf, bb->path); + strcat(pbuf, path); + } + + if (pbuf[strlen(pbuf)-1] != '/') + strcat(pbuf, "/"); + + while (1) { + char *p; + if ((p = strstr(pbuf, "/../"))) { + if (p == pbuf) return 0; + char *end = p + 3; + char *start = p - 1; + while (start > pbuf && *start != '/') --start; + memmove(start, end, strlen(end)+1); + continue; + } + if ((p = strstr(pbuf, "/./"))) { + memmove(p, p+2, strlen(p+2)+1); + continue; + } + break; + } + + if (chdir(pbuf)) return -1; + populate_files(bb, pbuf); + return 0; +} + /* * Remove all the files currently stored in bb->files and if `path` is non-NULL, * update `bb` with a listing of the files in `path` @@ -854,10 +901,15 @@ void populate_files(bb_t *bb, const char *path) if (!dir) err("Couldn't open dir: %s", path); + if (path != bb->path) + strcpy(bb->path, path); + + if (bb->path[strlen(bb->path)-1] != '/') + strcat(bb->path, "/"); + size_t cap = 0; char pathbuf[PATH_MAX]; - strcpy(pathbuf, path); - strcat(pathbuf, "/"); + strcpy(pathbuf, bb->path); size_t pathbuflen = strlen(pathbuf); for (struct dirent *dp; (dp = readdir(dir)) != NULL; ) { if (dp->d_name[0] == '.') { @@ -879,9 +931,6 @@ void populate_files(bb_t *bb, const char *path) } closedir(dir); - if (path != bb->path) - strcpy(bb->path, path); - // TODO: this may have some weird aliasing issues, but eh, it's simple and effective for (int i = 0; i < bb->nfiles; i++) bb->files[i]->shufflepos = rand(); @@ -917,40 +966,8 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd) case 'c': { // +cd:, +columns: switch (cmd[1]) { case 'd': { // +cd: - char pbuf[PATH_MAX]; - cd: if (!value) return BB_INVALID; - if (value[0] == '~') { - char *home; - if (!(home = getenv("HOME"))) - return BB_INVALID; - strcpy(pbuf, home); - strcat(pbuf, value+1); - value = pbuf; - } - char *rpbuf = realpath(value, NULL); - if (!rpbuf) return BB_INVALID; - if (strcmp(rpbuf, bb->path) == 0) { - free(rpbuf); - return BB_OK; - } - if (chdir(rpbuf)) { - free(rpbuf); - return BB_INVALID; - } - char *oldpath = memcheck(strdup(bb->path)); - populate_files(bb, rpbuf); - free(rpbuf); - if (strcmp(value, "..") == 0) { - entry_t *old = load_entry(bb, oldpath); - if (old) { - if (IS_VIEWED(old)) - set_cursor(bb, old->index); - else if (!IS_SELECTED(old)) - remove_entry(old); - } - } - free(oldpath); + if (cd_to(bb, value)) return BB_INVALID; return BB_OK; } case 'o': { // +columns: @@ -978,6 +995,7 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd) case 'd': { // +deselect:, +dotfiles: switch (cmd[1]) { case 'e': { // +deselect: + if (!value && !bb->nfiles) return BB_INVALID; if (!value) value = bb->files[bb->cursor]->name; if (strcmp(value, "*") == 0) { clear_selection(bb); @@ -1003,17 +1021,12 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd) set_cursor(bb, e->index); return BB_OK; } - char *real = realpath(e->fullname, NULL); - if (!real) return BB_INVALID; - char *lastslash = strrchr(real, '/'); - if (!lastslash) { - free(real); // estate - return BB_INVALID; - } + char pbuf[PATH_MAX]; + strcpy(pbuf, e->fullname); + char *lastslash = strrchr(pbuf, '/'); + if (!lastslash) return BB_INVALID; *lastslash = '\0'; // Split in two - if (chdir(real)) return BB_INVALID; - populate_files(bb, real); - free(real); // estate + cd_to(bb, pbuf); if (e->index >= 0) set_cursor(bb, e->index); return BB_OK; @@ -1023,7 +1036,9 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd) char key = value[0]; if (bb->marks[(int)key]) { value = bb->marks[(int)key]; - goto cd; + if (!value) return BB_INVALID; + if (cd_to(bb, value)) return BB_INVALID; + return BB_OK; } return BB_INVALID; } @@ -1045,6 +1060,7 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd) int oldcur, isdelta, n; move: if (!value) return BB_INVALID; + if (!bb->nfiles) return BB_INVALID; oldcur = bb->cursor; isdelta = value[0] == '-' || value[0] == '+'; n = (int)strtol(value, &value, 10); @@ -1085,6 +1101,7 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd) } case '\0': case 'e': // +select: + if (!value && !bb->nfiles) return BB_INVALID; if (!value) value = bb->files[bb->cursor]->name; if (strcmp(value, "*") == 0) { for (int i = 0; i < bb->nfiles; i++) { @@ -1108,6 +1125,7 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd) goto move; } case 't': { // +toggle: + if (!value && !bb->nfiles) return BB_INVALID; if (!value) value = bb->files[bb->cursor]->name; entry_t *e = load_entry(bb, value); if (e) toggle_entry(bb, e); @@ -1127,7 +1145,7 @@ void bb_browse(bb_t *bb, const char *path) int lastwidth = termwidth, lastheight = termheight; int check_cmds = 1; - populate_files(bb, path); + cd_to(bb, path); for (int i = 0; startupcmds[i]; i++) { if (startupcmds[i][0] == '+') { diff --git a/config.def.h b/config.def.h index b3b49ba..d454407 100644 --- a/config.def.h +++ b/config.def.h @@ -114,7 +114,7 @@ binding_t bindings[] = { // Please note that these are sh scripts, not bash scripts, so bash-isms // won't work unless you make your script use `bash -c ""` ////////////////////////////////////////////////////////////////////////// - {{'?'}, "bb -b | $PAGER -r", "Show the help menu", NORMAL_TERM}, + {{'?', KEY_F1}, "bb -b | $PAGER -r", "Show the help menu", NORMAL_TERM}, {{'q', 'Q'}, "+quit", "Quit"}, {{'k', KEY_ARROW_UP}, "+move:-1", "Move up"}, {{'j', KEY_ARROW_DOWN}, "+move:+1", "Move down"},