Cleaned up and deduplicated some of the path normalization code.

This commit is contained in:
Bruce Hill 2019-06-15 18:13:44 -07:00
parent 302ed33d9c
commit 4c717185de

77
bb.c
View File

@ -132,9 +132,9 @@ static int compare_files(const void *v1, const void *v2, void *v);
static void deselect_entry(bb_t *bb, entry_t *e);
static int fputs_escaped(FILE *f, const char *str, const char *color);
static void init_term(void);
static entry_t* load_entry(bb_t *bb, const char *path);
static entry_t* load_entry(bb_t *bb, const char *path, int clear_dots);
static void* memcheck(void *p);
static void normalize_path(const char *root, const char *path, char *pbuf);
static void normalize_path(const char *root, const char *path, char *pbuf, int clear_dots);
static void populate_files(bb_t *bb, const char *path);
static void print_bindings(void);
static bb_result_t process_cmd(bb_t *bb, const char *cmd);
@ -714,24 +714,13 @@ void set_scroll(bb_t *bb, int newscroll)
* Warning: this does not deduplicate entries, and it's best if there aren't
* duplicate entries hanging around.
*/
entry_t* load_entry(bb_t *bb, const char *path)
entry_t* load_entry(bb_t *bb, const char *path, int clear_dots)
{
struct stat linkedstat, filestat;
if (!path || !path[0]) return NULL;
if (lstat(path, &filestat) == -1) return NULL;
char pbuf[PATH_MAX];
if (path[0] == '~' && (path[1] == '\0' || path[1] == '/')) {
char *home;
if (!(home = getenv("HOME")))
return NULL;
strcpy(pbuf, home);
strcat(pbuf, path+1);
} else if (path[0] == '/') {
strcpy(pbuf, path);
} else {
strcpy(pbuf, bb->path);
strcat(pbuf, path);
}
normalize_path(bb->path, path, pbuf, clear_dots);
if (pbuf[strlen(pbuf)-1] == '/' && pbuf[1])
pbuf[strlen(pbuf)-1] = '\0';
@ -808,11 +797,11 @@ void sort_files(bb_t *bb)
}
/*
* Prepend `root` to relative paths, replace "~" with $HOME, replace "/foo/."
* with "/foo", replace "/foo/baz/.." with "/foo".
* Prepend `root` to relative paths, replace "~" with $HOME.
* If clear_dots is 1, then also replace "/foo/." with "/foo" and replace "/foo/baz/.." with "/foo".
* The normalized path is stored in `normalized`.
*/
void normalize_path(const char *root, const char *path, char *normalized)
void normalize_path(const char *root, const char *path, char *normalized, int clear_dots)
{
if (path[0] == '~' && (path[1] == '\0' || path[1] == '/')) {
char *home;
@ -826,21 +815,23 @@ void normalize_path(const char *root, const char *path, char *normalized)
}
strcat(normalized, path);
char *src = normalized, *dest = normalized;
while (*src) {
while (src[0] == '/' && src[1] == '.') {
// Replace "foo/./?" with "foo/?"
if (src[2] == '/' || src[2] == '\0') {
src += 2;
} else if (src[2] == '.' && (src[3] == '/' || src[3] == '\0')) {
// Replace "foo/baz/../?" with "foo/?"
src += 3;
while (dest > normalized && *(--dest) != '/');
} else break;
if (clear_dots) {
char *src = normalized, *dest = normalized;
while (*src) {
while (src[0] == '/' && src[1] == '.') {
// Replace "foo/./?" with "foo/?"
if (src[2] == '/' || src[2] == '\0') {
src += 2;
} else if (src[2] == '.' && (src[3] == '/' || src[3] == '\0')) {
// Replace "foo/baz/../?" with "foo/?"
src += 3;
while (dest > normalized && *(--dest) != '/');
} else break;
}
*(dest++) = *(src++);
}
*(dest++) = *(src++);
*dest = '\0';
}
*dest = '\0';
}
int cd_to(bb_t *bb, const char *path)
@ -856,7 +847,7 @@ int cd_to(bb_t *bb, const char *path)
strcpy(pbuf, bb->marks['-']);
if (chdir(pbuf)) return -1;
} else {
normalize_path(bb->path, path, pbuf);
normalize_path(bb->path, path, pbuf, 1);
if (pbuf[strlen(pbuf)-1] != '/')
strcat(pbuf, "/");
if (chdir(pbuf)) return -1;
@ -869,7 +860,7 @@ int cd_to(bb_t *bb, const char *path)
populate_files(bb, pbuf);
if (prev[0]) {
entry_t *p = load_entry(bb, prev);
entry_t *p = load_entry(bb, prev, 0);
if (p) {
if (IS_VIEWED(p)) set_cursor(bb, p->index);
else try_free_entry(p);
@ -937,7 +928,7 @@ void populate_files(bb_t *bb, const char *path)
bb->files = memcheck(realloc(bb->files, (space += 100)*sizeof(void*)));
strcpy(&pathbuf[pathbuflen], dp->d_name);
// Don't normalize path so we can get "." and ".."
entry_t *entry = load_entry(bb, pathbuf);
entry_t *entry = load_entry(bb, pathbuf, 0);
if (!entry) err("Failed to load entry: '%s'", dp->d_name);
entry->index = bb->nfiles;
bb->files[bb->nfiles++] = entry;
@ -1020,8 +1011,8 @@ bb_result_t process_cmd(bb_t *bb, const char *cmd)
if (!value && !bb->nfiles) return BB_INVALID;
if (!value) value = bb->files[bb->cursor]->fullname;
char pbuf[PATH_MAX];
normalize_path(bb->path, value, pbuf);
entry_t *e = load_entry(bb, pbuf);
normalize_path(bb->path, value, pbuf, 1);
entry_t *e = load_entry(bb, pbuf, 0);
if (e) {
deselect_entry(bb, e);
return BB_OK;
@ -1044,7 +1035,7 @@ bb_result_t process_cmd(bb_t *bb, const char *cmd)
}
case 'g': { // +goto:
if (!value) return BB_INVALID;
entry_t *e = load_entry(bb, value);
entry_t *e = load_entry(bb, value, 1);
if (!e) return BB_INVALID;
if (IS_VIEWED(e)) {
set_cursor(bb, e->index);
@ -1056,8 +1047,6 @@ 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);
e = load_entry(bb, lastslash+1);
if (!e) return BB_INVALID;
if (IS_VIEWED(e)) {
set_cursor(bb, e->index);
return BB_OK;
@ -1143,9 +1132,7 @@ bb_result_t process_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]->fullname;
char pbuf[PATH_MAX];
normalize_path(bb->path, value, pbuf);
entry_t *e = load_entry(bb, pbuf);
entry_t *e = load_entry(bb, value, 1);
if (e) select_entry(bb, e);
return BB_OK;
}
@ -1161,9 +1148,7 @@ bb_result_t process_cmd(bb_t *bb, const char *cmd)
case 't': { // +toggle:
if (!value && !bb->nfiles) return BB_INVALID;
if (!value) value = bb->files[bb->cursor]->fullname;
char pbuf[PATH_MAX];
normalize_path(bb->path, value, pbuf);
entry_t *e = load_entry(bb, pbuf);
entry_t *e = load_entry(bb, value, 1);
if (e) toggle_entry(bb, e);
return BB_OK;
}
@ -1511,7 +1496,7 @@ int main(int argc, char *argv[])
char path[PATH_MAX], curdir[PATH_MAX];
getcwd(curdir, PATH_MAX);
strcat(curdir, "/");
normalize_path(curdir, initial_path, path);
normalize_path(curdir, initial_path, path, 1);
if (chdir(path)) err("Not a valid path: %s\n", path);
bb_t *bb = memcheck(calloc(1, sizeof(bb_t)));