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.
This commit is contained in:
Bruce Hill 2019-05-31 12:47:35 -07:00
parent e11158a69f
commit f539538582
2 changed files with 75 additions and 57 deletions

130
bb.c
View File

@ -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] == '+') {

View File

@ -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 "<your script>"`
//////////////////////////////////////////////////////////////////////////
{{'?'}, "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"},