From 33b951f3b5d89c0ba7e7c7d821a9eafb37088872 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sun, 24 Jan 2021 12:39:45 -0500 Subject: auto-cd: check if actually directory, ~ --- main.c | 7 +++++++ ted-base.c | 10 --------- ted.h | 13 ++++++++++++ ui.c | 70 ++++++++++++++++++++++++++++++++++++++++++++------------------ 4 files changed, 70 insertions(+), 30 deletions(-) diff --git a/main.c b/main.c index f04f984..ca8c991 100644 --- a/main.c +++ b/main.c @@ -95,8 +95,15 @@ int main(int argc, char **argv) { strbuf_printf(ted_local_data_dir, "%ls" PATH_SEPARATOR_STR "ted", appdata); CoTaskMemFree(appdata); } + id = FOLDERID_Profile; + wchar_t *home = NULL; + if (SHGetKnownFolderPath(&id, 0, NULL, &home) == S_OK) { + strbuf_printf(ted_home, "%ls", home); + CoTaskMemFree(home); + } #else char *home = getenv("HOME"); + strbuf_printf(ted_home, "%s", home); strbuf_printf(ted_local_data_dir, "%s/.local/share/ted", home); #endif } diff --git a/ted-base.c b/ted-base.c index d8acf0c..80d14e3 100644 --- a/ted-base.c +++ b/ted-base.c @@ -38,16 +38,6 @@ static void *ted_realloc(Ted *ted, void *p, size_t new_size) { return ret; } -// should the working directory be searched for files? set to true if the executable isn't "installed" -static bool ted_search_cwd = false; -static char const ted_global_data_dir[] = -#if _WIN32 - "C:\\Program Files\\ted"; -#else - "/usr/share/ted"; -#endif -static char ted_local_data_dir[TED_PATH_MAX]; // filled out in main() - // Check the various places a file could be, and return the full path. static Status ted_get_file(char const *name, char *out, size_t outsz) { if (ted_search_cwd && fs_file_exists(name)) { diff --git a/ted.h b/ted.h index d33c460..077d32d 100644 --- a/ted.h +++ b/ted.h @@ -114,3 +114,16 @@ typedef struct Ted { char cwd[TED_PATH_MAX]; // current working directory char error[256]; } Ted; + +// should the working directory be searched for files? set to true if the executable isn't "installed" +static bool ted_search_cwd = false; +static char const ted_global_data_dir[] = +#if _WIN32 + "C:\\Program Files\\ted"; +#else + "/usr/share/ted"; +#endif + +// filled out in main() +static char ted_local_data_dir[TED_PATH_MAX]; +static char ted_home[TED_PATH_MAX]; // home directory -- this is what ~ expands to diff --git a/ui.c b/ui.c index 1e6702c..87f2175 100644 --- a/ui.c +++ b/ui.c @@ -46,15 +46,25 @@ static int qsort_file_entry_cmp(void const *av, void const *bv) { return strcmp_case_insensitive(a->name, b->name); } -static void file_selector_cd_(FileSelector *fs, char const *path, int symlink_depth); +static Status file_selector_cd_(FileSelector *fs, char const *path, int symlink_depth); // cd to the directory `name`. `name` cannot include any path separators. -static void file_selector_cd1(FileSelector *fs, char const *name, size_t name_len, int symlink_depth) { +static Status file_selector_cd1(FileSelector *fs, char const *name, size_t name_len, int symlink_depth) { char *const cwd = fs->cwd; if (name_len == 0 || (name_len == 1 && name[0] == '.')) { // no name, or . - return; + return true; + } + + if (name_len == 1 && name[0] == '~') { + // just in case the user's HOME happens to be accidentally set to, e.g. '/foo/~', make + // sure we don't recurse infinitely + if (symlink_depth < 32) { + return file_selector_cd_(fs, ted_home, symlink_depth + 1); + } else { + return false; + } } if (name_len == 2 && name[0] == '.' && name[1] == '.') { @@ -72,37 +82,46 @@ static void file_selector_cd1(FileSelector *fs, char const *name, size_t name_le } } } else { - #if __unix__ - if (symlink_depth < 32) { // on my system, MAXSYMLINKS is 20, so this should be plenty - char path[TED_PATH_MAX], link_to[TED_PATH_MAX]; - // join fs->cwd with name to get full path - str_printf(path, TED_PATH_MAX, "%s%s%*s", cwd, + char path[TED_PATH_MAX]; + // join fs->cwd with name to get full path + str_printf(path, TED_PATH_MAX, "%s%s%*s", cwd, cwd[strlen(cwd) - 1] == PATH_SEPARATOR ? "" : PATH_SEPARATOR_STR, (int)name_len, name); + if (fs_path_type(path) != FS_DIRECTORY) { + // trying to cd to something that's not a directory! + return false; + } + + #if __unix__ + if (symlink_depth < 32) { // on my system, MAXSYMLINKS is 20, so this should be plenty + char link_to[TED_PATH_MAX]; ssize_t bytes = readlink(path, link_to, sizeof link_to); if (bytes != -1) { // this is a symlink link_to[bytes] = '\0'; - file_selector_cd_(fs, link_to, symlink_depth + 1); - return; + return file_selector_cd_(fs, link_to, symlink_depth + 1); } + } else { + return false; } #else (void)symlink_depth; #endif + // add path separator to end if not already there (which could happen in the case of /) if (cwd[strlen(cwd) - 1] != PATH_SEPARATOR) str_cat(cwd, sizeof fs->cwd, PATH_SEPARATOR_STR); // add name itself strn_cat(cwd, sizeof fs->cwd, name, name_len); } + return true; } -static void file_selector_cd_(FileSelector *fs, char const *path, int symlink_depth) { +static Status file_selector_cd_(FileSelector *fs, char const *path, int symlink_depth) { char *const cwd = fs->cwd; - if (path[0] == '\0') return; + if (path[0] == '\0') return true; if (path[0] == PATH_SEPARATOR #if _WIN32 @@ -128,16 +147,19 @@ static void file_selector_cd_(FileSelector *fs, char const *path, int symlink_de while (*p) { size_t len = strcspn(p, PATH_SEPARATOR_STR); - file_selector_cd1(fs, p, len, symlink_depth); + if (!file_selector_cd1(fs, p, len, symlink_depth)) + return false; p += len; p += strspn(p, PATH_SEPARATOR_STR); } + return true; } // go to the directory `path`. make sure `path` only contains path separators like PATH_SEPARATOR, not any // other members of ALL_PATH_SEPARATORS -static void file_selector_cd(FileSelector *fs, char const *path) { - file_selector_cd_(fs, path, 0); +// returns false if this path doesn't exist or isn't a directory +static bool file_selector_cd(FileSelector *fs, char const *path) { + return file_selector_cd_(fs, path, 0); } // returns the name of the selected file, or NULL @@ -154,11 +176,14 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { // check if the search term contains a path separator. if so, cd to the dirname. - u32 last_path_sep = U32_MAX; + u32 first_path_sep = U32_MAX, last_path_sep = U32_MAX; for (u32 i = 0; i < search_term32.len; ++i) { char32_t c = search_term32.str[i]; - if (c < CHAR_MAX && strchr(ALL_PATH_SEPARATORS, (char)c)) + if (c < CHAR_MAX && strchr(ALL_PATH_SEPARATORS, (char)c)) { last_path_sep = i; + if (first_path_sep == U32_MAX) + first_path_sep = i; + } } if (last_path_sep != U32_MAX) { @@ -171,9 +196,14 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { if (strchr(ALL_PATH_SEPARATORS, *p)) *p = PATH_SEPARATOR; - file_selector_cd(fs, dir_name); - buffer_delete_chars_at_pos(line_buffer, buffer_start_of_file(line_buffer), last_path_sep + 1); // delete up to and including the last path separator - buffer_clear_undo_redo(line_buffer); + if (file_selector_cd(fs, dir_name)) { + buffer_delete_chars_at_pos(line_buffer, buffer_start_of_file(line_buffer), last_path_sep + 1); // delete up to and including the last path separator + buffer_clear_undo_redo(line_buffer); + } else { + BufferPos pos = {.line = 0, .index = first_path_sep}; + size_t nchars = search_term32.len - first_path_sep; + buffer_delete_chars_at_pos(line_buffer, pos, (i64)nchars); + } } } -- cgit v1.2.3