int paths_are_same(const char s[], const char t[]) { char s_real[PATH_MAX]; char t_real[PATH_MAX]; if(os_realpath(s, s_real) != s_real || os_realpath(t, t_real) != t_real) { return (stroscmp(s, t) == 0); } return (stroscmp(s_real, t_real) == 0); }
/* Compares two file names according to symbolic link target. Returns standard * -1, 0, 1 for comparisons. */ static int compare_targets(const dir_entry_t *f, const dir_entry_t *s) { char full_path[PATH_MAX + 1]; char nlink[PATH_MAX + 1], plink[PATH_MAX + 1]; if((f->type == FT_LINK) != (s->type == FT_LINK)) { /* One of the entries is not a link. */ return (f->type == FT_LINK) ? 1 : -1; } if(f->type != FT_LINK) { /* Both entries are not symbolic links. */ return 0; } /* Both entries are symbolic links. */ get_full_path_of(f, sizeof(full_path), full_path); if(get_link_target(full_path, nlink, sizeof(nlink)) != 0) { return 0; } get_full_path_of(s, sizeof(full_path), full_path); if(get_link_target(full_path, plink, sizeof(plink)) != 0) { return 0; } return stroscmp(nlink, plink); }
/* Sorting function for qsort(). */ static int sorter(const void *first, const void *second) { const char *stra = *(const char **)first; const char *strb = *(const char **)second; return stroscmp(stra, strb); }
int show_history_menu(FileView *view) { int i; static menu_info m; init_menu_info(&m, DIRHISTORY, strdup("History disabled or empty")); m.title = strdup(" Directory History "); for(i = 0; i < view->history_num && i < cfg.history_len; i++) { int j; if(view->history[i].dir[0] == '\0') break; for(j = i + 1; j < view->history_num && j < cfg.history_len; j++) if(stroscmp(view->history[i].dir, view->history[j].dir) == 0) break; if(j < view->history_num && j < cfg.history_len) continue; if(!is_valid_dir(view->history[i].dir)) continue; /* Change the current dir to reflect the current file. */ if(stroscmp(view->history[i].dir, view->curr_dir) == 0) { (void)replace_string(&view->history[i].file, view->dir_entry[view->list_pos].name); m.pos = m.len; } m.len = add_to_string_array(&m.items, m.len, 1, view->history[i].dir); } /* Reverse order in which items appear. */ for(i = 0; i < m.len/2; i++) { char *t = m.items[i]; m.items[i] = m.items[m.len - 1 - i]; m.items[m.len - 1 - i] = t; } m.pos = m.len - 1 - m.pos; return display_menu(&m, view); }
int flist_find_entry(const FileView *view, const char file[], const char dir[]) { int i; for(i = 0; i < view->list_rows; ++i) { if(dir != NULL && stroscmp(view->dir_entry[i].origin, dir) != 0) { continue; } if(stroscmp(view->dir_entry[i].name, file) == 0) { return i; } } return -1; }
int is_in_trash(const char trash_name[]) { int i; for(i = 0; i < nentries; i++) { if(stroscmp(trash_list[i].trash_name, trash_name) == 0) return 1; } return 0; }
/* searches for existent variable */ static envvar_t * find_record(const char *name) { int i; for(i = 0; i < nvars; i++) { if(vars[i].name != NULL && stroscmp(vars[i].name, name) == 0) return &vars[i]; } return NULL; }
int paths_are_equal(const char s[], const char t[]) { /* Some additional space is allocated for adding slashes. */ char s_can[strlen(s) + 8]; char t_can[strlen(t) + 8]; canonicalize_path(s, s_can, sizeof(s_can)); canonicalize_path(t, t_can, sizeof(t_can)); return stroscmp(s_can, t_can) == 0; }
char * fast_run_complete(const char cmd[]) { char *result = NULL; const char *args; char command[NAME_MAX]; char *completed; args = extract_cmd_name(cmd, 0, sizeof(command), command); if(is_path_absolute(command)) { return strdup(cmd); } vle_compl_reset(); complete_command_name(command); vle_compl_unite_groups(); completed = vle_compl_next(); if(vle_compl_get_count() > 2) { int c = vle_compl_get_count() - 1; while(c-- > 0) { if(stroscmp(command, completed) == 0) { result = strdup(cmd); break; } else { free(completed); completed = vle_compl_next(); } } if(result == NULL) { status_bar_error("Command beginning is ambiguous"); } } else { free(completed); completed = vle_compl_next(); result = format_str("%s %s", completed, args); } free(completed); return result; }
int vifm_chdir(const char path[]) { char curr_path[PATH_MAX]; if(getcwd(curr_path, sizeof(curr_path)) == curr_path) { if(stroscmp(curr_path, path) == 0) { return 0; } } return os_chdir(path); }
static int check_for_duplicate_file_names(reg_t *reg, const char file[]) { int i; for(i = 0; i < reg->nfiles; ++i) { if(stroscmp(file, reg->files[i]) == 0) { return 1; } } return 0; }
int check_mark_directory(FileView *view, char mark) { const bookmark_t *const bmark = get_bookmark(mark); if(!is_bmark_empty(bmark)) { if(stroscmp(view->curr_dir, bmark->directory) == 0) { return find_file_pos_in_list(view, bmark->file); } } return -1; }
/* Checks if PATH environment variable was changed. Returns non-zero if path was * altered since last call. */ static int path_env_was_changed(int force) { const char *path; path = local_getenv("PATH"); if(clean_path != NULL && stroscmp(clean_path, path) == 0) { return force; } (void)replace_string(&clean_path, path); return 1; }
int is_root_dir(const char *path) { #ifdef _WIN32 if(isalpha(path[0]) && stroscmp(path + 1, ":/") == 0) return 1; if(path[0] == '/' && path[1] == '/' && path[2] != '\0') { char *p = strchr(path + 2, '/'); if(p == NULL || p[1] == '\0') return 1; } #endif return (path[0] == '/' && path[1] == '\0'); }
int bmark_is_older(const char path[], time_t than) { size_t i; char canonic_path[strlen(path) + 16U]; make_canonic(path, canonic_path, sizeof(canonic_path)); for(i = 0U; i < bmark_count; ++i) { if(stroscmp(canonic_path, bmarks[i].path) == 0) { return bmarks[i].timestamp < than; } } return 1; }
void bmarks_file_moved(const char src[], const char dst[]) { size_t i; char canonic_src[strlen(src) + 16U], canonic_dst[strlen(dst) + 16U]; make_canonic(src, canonic_src, sizeof(canonic_src)); make_canonic(dst, canonic_dst, sizeof(canonic_dst)); /* Renames bookmark. */ for(i = 0U; i < bmark_count; ++i) { if(stroscmp(canonic_src, bmarks[i].path) == 0) { (void)replace_string(&bmarks[i].path, canonic_dst); break; } } }
char * cut_extension(char path[]) { char *e; char *ext; if((ext = strrchr(path, '.')) == NULL) return path + strlen(path); *ext = '\0'; if((e = strrchr(path, '.')) != NULL && stroscmp(e + 1, "tar") == 0) { *ext = '.'; ext = e; } *ext = '\0'; return ext + 1; }
/* Changes value of existing bookmark. When value was found *ret is set to * error code. Returns non-zero if value was found and zero otherwise. */ static int change_bmark(const char path[], const char tags[], time_t timestamp, int *ret) { size_t i; char canonic_path[strlen(path) + 16U]; make_canonic(path, canonic_path, sizeof(canonic_path)); /* Try to update tags of an existing bookmark. */ for(i = 0U; i < bmark_count; ++i) { if(stroscmp(canonic_path, bmarks[i].path) == 0) { *ret = replace_string(&bmarks[i].tags, tags); if(*ret == 0) { bmarks[i].timestamp = timestamp; } return 0; } } return 1; }
/* Either makes use of abandoned view or prunes it. Returns zero on success, * otherwise non-zero is returned. */ static int try_ressurect_abandoned(const char full_path[], int explore) { const int same_file = vi->abandoned && vi->view == (explore ? curr_view : other_view) && vi->filename != NULL && stroscmp(vi->filename, full_path) == 0; if(!same_file) { return 1; } if(explore) { vi->view->explore_mode = 0; reset_view_info(vi); return 1; } else { vle_mode_set(VIEW_MODE, VMT_SECONDARY); return 0; } }
void vifm_restart(void) { FileView *tmp_view; curr_stats.restart_in_progress = 1; /* All user mappings in all modes. */ vle_keys_user_clear(); /* User defined commands. */ execute_cmd("comclear"); /* Autocommands. */ vle_aucmd_remove(NULL, NULL); /* Directory histories. */ ui_view_clear_history(&lwin); ui_view_clear_history(&rwin); /* All kinds of history. */ (void)hist_reset(&cfg.search_hist, cfg.history_len); (void)hist_reset(&cfg.cmd_hist, cfg.history_len); (void)hist_reset(&cfg.prompt_hist, cfg.history_len); (void)hist_reset(&cfg.filter_hist, cfg.history_len); cfg.history_len = 0; /* Session status. Must be reset _before_ options, because options take some * of values from status. */ (void)reset_status(&cfg); /* Options of current pane. */ reset_options_to_default(); /* Options of other pane. */ tmp_view = curr_view; curr_view = other_view; load_view_options(other_view); reset_options_to_default(); curr_view = tmp_view; /* File types and viewers. */ ft_reset(curr_stats.exec_env_type == EET_EMULATOR_WITH_X); /* Undo list. */ reset_undo_list(); /* Directory stack. */ dir_stack_clear(); /* Registers. */ regs_reset(); /* Clear all marks and bookmarks. */ clear_all_marks(); bmarks_clear(); /* Reset variables. */ clear_envvars(); init_variables(); /* This update is needed as clear_variables() will reset $PATH. */ update_path_env(1); reset_views(); read_info_file(1); flist_hist_save(&lwin, NULL, NULL, -1); flist_hist_save(&rwin, NULL, NULL, -1); /* Color schemes. */ if(stroscmp(curr_stats.color_scheme, DEF_CS_NAME) != 0 && cs_exists(curr_stats.color_scheme)) { if(cs_load_primary(curr_stats.color_scheme) != 0) { cs_load_defaults(); } } else { cs_load_defaults(); } cs_load_pairs(); cfg_load(); exec_startup_commands(&vifm_args); curr_stats.restart_in_progress = 0; /* Trigger auto-commands for initial directories. */ vle_aucmd_execute("DirEnter", lwin.curr_dir, &lwin); vle_aucmd_execute("DirEnter", rwin.curr_dir, &rwin); update_screen(UT_REDRAW); }
/* Breaks PATH environment variable into list of paths. */ static void split_path_list(void) { const char *path, *p, *q; int i; path = env_get("PATH"); if(paths != NULL) free_string_array(paths, paths_count); paths_count = 1; p = path; while((p = strchr(p, ':')) != NULL) { paths_count++; p++; } paths = reallocarray(NULL, paths_count, sizeof(paths[0])); if(paths == NULL) { paths_count = 0; return; } i = 0; p = path - 1; do { int j; char *s; p++; #ifndef _WIN32 q = strchr(p, ':'); #else q = strchr(p, ';'); #endif if(q == NULL) { q = p + strlen(p); } s = malloc(q - p + 1U); if(s == NULL) { free_string_array(paths, i - 1); paths = NULL; paths_count = 0; return; } copy_str(s, q - p + 1U, p); p = q; s = replace_tilde(s); /* No need to check "." path for existence. */ if(strcmp(s, ".") != 0) { if(!path_exists(s, DEREF)) { free(s); continue; } } paths[i++] = s; for(j = 0; j < i - 1; j++) { if(stroscmp(paths[j], s) == 0) { free(s); i--; break; } } } while(q[0] != '\0'); paths_count = i; }
/* * type: CT_* */ void filename_completion(const char *str, CompletionType type) { /* TODO refactor filename_completion(...) function */ DIR * dir; char * dirname; char * filename; char * temp; if(str[0] == '~' && strchr(str, '/') == NULL) { char *const tilde_expanded = expand_tilde(str); vle_compl_add_path_match(tilde_expanded); free(tilde_expanded); return; } dirname = expand_tilde(str); filename = strdup(dirname); temp = cmds_expand_envvars(dirname); free(dirname); dirname = temp; temp = strrchr(dirname, '/'); if(temp != NULL && type != CT_FILE && type != CT_FILE_WOE) { strcpy(filename, ++temp); *temp = '\0'; } else { dirname = realloc(dirname, 2); strcpy(dirname, "."); } #ifdef _WIN32 if(is_unc_root(dirname) || (stroscmp(dirname, ".") == 0 && is_unc_root(curr_view->curr_dir)) || (stroscmp(dirname, "/") == 0 && is_unc_path(curr_view->curr_dir))) { char buf[PATH_MAX]; if(!is_unc_root(dirname)) snprintf(buf, strchr(curr_view->curr_dir + 2, '/') - curr_view->curr_dir + 1, "%s", curr_view->curr_dir); else snprintf(buf, sizeof(buf), "%s", dirname); complete_with_shared(buf, filename); free(filename); free(dirname); return; } if(is_unc_path(curr_view->curr_dir)) { char buf[PATH_MAX]; if(is_path_absolute(dirname) && !is_unc_root(curr_view->curr_dir)) snprintf(buf, strchr(curr_view->curr_dir + 2, '/') - curr_view->curr_dir + 2, "%s", curr_view->curr_dir); else snprintf(buf, sizeof(buf), "%s", curr_view->curr_dir); strcat(buf, dirname); chosp(buf); (void)replace_string(&dirname, buf); } #endif dir = opendir(dirname); if(dir == NULL || vifm_chdir(dirname) != 0) { vle_compl_add_path_match(filename); } else { filename_completion_internal(dir, dirname, filename, type); (void)vifm_chdir(curr_view->curr_dir); } free(filename); free(dirname); if(dir != NULL) { closedir(dir); } }
void vifm_restart(void) { view_t *tmp_view; curr_stats.restart_in_progress = 1; /* All user mappings in all modes. */ vle_keys_user_clear(); /* User defined commands. */ vle_cmds_run("comclear"); /* Autocommands. */ vle_aucmd_remove(NULL, NULL); /* All kinds of histories. */ cfg_resize_histories(0); /* Session status. Must be reset _before_ options, because options take some * of values from status. */ (void)stats_reset(&cfg); /* Options of current pane. */ vle_opts_restore_defaults(); /* Options of other pane. */ tmp_view = curr_view; curr_view = other_view; load_view_options(other_view); vle_opts_restore_defaults(); curr_view = tmp_view; /* File types and viewers. */ ft_reset(curr_stats.exec_env_type == EET_EMULATOR_WITH_X); /* Undo list. */ un_reset(); /* Directory stack. */ dir_stack_clear(); /* Registers. */ regs_reset(); /* Clear all marks and bookmarks. */ clear_all_marks(); bmarks_clear(); /* Reset variables. */ clear_envvars(); init_variables(); /* This update is needed as clear_variables() will reset $PATH. */ update_path_env(1); reset_views(); read_info_file(1); flist_hist_save(&lwin, NULL, NULL, -1); flist_hist_save(&rwin, NULL, NULL, -1); /* Color schemes. */ if(stroscmp(curr_stats.color_scheme, DEF_CS_NAME) != 0 && cs_exists(curr_stats.color_scheme)) { cs_load_primary(curr_stats.color_scheme); } else { cs_load_defaults(); } cs_load_pairs(); cfg_load(); /* Reloading of tabs needs to happen after configuration is read so that new * values from lwin and rwin got propagated. */ tabs_reload(); exec_startup_commands(&vifm_args); curr_stats.restart_in_progress = 0; /* Trigger auto-commands for initial directories. */ (void)vifm_chdir(flist_get_dir(&lwin)); vle_aucmd_execute("DirEnter", flist_get_dir(&lwin), &lwin); (void)vifm_chdir(flist_get_dir(&rwin)); vle_aucmd_execute("DirEnter", flist_get_dir(&rwin), &rwin); update_screen(UT_REDRAW); }
/* Composes side-by-side comparison of files in two views. */ static void fill_side_by_side(entries_t curr, entries_t other, int group_paths) { enum { UP, LEFT, DIAG }; int i, j; /* Describes results of solving sub-problems. */ int (*d)[other.nentries + 1] = reallocarray(NULL, curr.nentries + 1, sizeof(*d)); /* Describes paths (backtracking handles ambiguity badly). */ char (*p)[other.nentries + 1] = reallocarray(NULL, curr.nentries + 1, sizeof(*p)); for(i = 0; i <= curr.nentries; ++i) { for(j = 0; j <= other.nentries; ++j) { if(i == 0) { d[i][j] = j; p[i][j] = LEFT; } else if(j == 0) { d[i][j] = i; p[i][j] = UP; } else { const dir_entry_t *centry = &curr.entries[curr.nentries - i]; const dir_entry_t *oentry = &other.entries[other.nentries - j]; d[i][j] = MIN(d[i - 1][j] + 1, d[i][j - 1] + 1); p[i][j] = d[i][j] == d[i - 1][j] + 1 ? UP : LEFT; if((centry->id == oentry->id || (group_paths && stroscmp(centry->name, oentry->name) == 0)) && d[i - 1][j - 1] <= d[i][j]) { d[i][j] = d[i - 1][j - 1]; p[i][j] = DIAG; } } } } i = curr.nentries; j = other.nentries; while(i != 0 || j != 0) { switch(p[i][j]) { dir_entry_t *e; case UP: e = &curr.entries[curr.nentries - 1 - --i]; flist_custom_put(curr_view, e); flist_custom_add_separator(other_view, e->id); break; case LEFT: e = &other.entries[other.nentries - 1 - --j]; flist_custom_put(other_view, e); flist_custom_add_separator(curr_view, e->id); break; case DIAG: flist_custom_put(curr_view, &curr.entries[curr.nentries - 1 - --i]); flist_custom_put(other_view, &other.entries[other.nentries - 1 - --j]); break; } } free(d); free(p); /* Entries' data has been moved out of them, so need to free only the * lists. */ dynarray_free(curr.entries); dynarray_free(other.entries); }
static int prog_exists(const char *name) { return stroscmp(name, "console") == 0; }
int flist_find_group(const FileView *view, int next) { /* TODO: refactor/simplify this function (flist_find_group()). */ const int correction = next ? -1 : 0; const int lb = correction; const int ub = view->list_rows + correction; const int inc = next ? +1 : -1; int pos = view->list_pos; dir_entry_t *pentry = &view->dir_entry[pos]; const char *ext = get_last_ext(pentry->name); size_t char_width = utf8_chrw(pentry->name); wchar_t ch = towupper(get_first_wchar(pentry->name)); const SortingKey sorting_key = flist_custom_active(view) && cv_compare(view->custom.type) ? SK_BY_ID : abs(view->sort[0]); const int is_dir = fentry_is_dir(pentry); const char *const type_str = get_type_str(pentry->type); regmatch_t pmatch = { .rm_so = 0, .rm_eo = 0 }; #ifndef _WIN32 char perms[16]; get_perm_string(perms, sizeof(perms), pentry->mode); #endif if(sorting_key == SK_BY_GROUPS) { pmatch = get_group_match(&view->primary_group, pentry->name); } while(pos > lb && pos < ub) { dir_entry_t *nentry; pos += inc; nentry = &view->dir_entry[pos]; switch(sorting_key) { case SK_BY_FILEEXT: if(fentry_is_dir(nentry)) { if(strncmp(pentry->name, nentry->name, char_width) != 0) { return pos; } } if(strcmp(get_last_ext(nentry->name), ext) != 0) { return pos; } break; case SK_BY_EXTENSION: if(strcmp(get_last_ext(nentry->name), ext) != 0) return pos; break; case SK_BY_GROUPS: { regmatch_t nmatch = get_group_match(&view->primary_group, nentry->name); if(pmatch.rm_eo - pmatch.rm_so != nmatch.rm_eo - nmatch.rm_so || (pmatch.rm_eo != pmatch.rm_so && strncmp(pentry->name + pmatch.rm_so, nentry->name + nmatch.rm_so, pmatch.rm_eo - pmatch.rm_so + 1U) != 0)) return pos; } break; case SK_BY_TARGET: if((nentry->type == FT_LINK) != (pentry->type == FT_LINK)) { /* One of the entries is not a link. */ return pos; } if(nentry->type == FT_LINK) { /* Both entries are symbolic links. */ char full_path[PATH_MAX]; char nlink[PATH_MAX], plink[PATH_MAX]; get_full_path_of(nentry, sizeof(full_path), full_path); if(get_link_target(full_path, nlink, sizeof(nlink)) != 0) { return pos; } get_full_path_of(pentry, sizeof(full_path), full_path); if(get_link_target(full_path, plink, sizeof(plink)) != 0) { return pos; } if(stroscmp(nlink, plink) != 0) { return pos; } } break; case SK_BY_NAME: if(strncmp(pentry->name, nentry->name, char_width) != 0) return pos; break; case SK_BY_INAME: if((wchar_t)towupper(get_first_wchar(nentry->name)) != ch) return pos; break; case SK_BY_SIZE: if(nentry->size != pentry->size) return pos; break; case SK_BY_NITEMS: if(entry_get_nitems(view, nentry) != entry_get_nitems(view, pentry)) return pos; break; case SK_BY_TIME_ACCESSED: if(nentry->atime != pentry->atime) return pos; break; case SK_BY_TIME_CHANGED: if(nentry->ctime != pentry->ctime) return pos; break; case SK_BY_TIME_MODIFIED: if(nentry->mtime != pentry->mtime) return pos; break; case SK_BY_DIR: if(is_dir != fentry_is_dir(nentry)) { return pos; } break; case SK_BY_TYPE: if(get_type_str(nentry->type) != type_str) { return pos; } break; #ifndef _WIN32 case SK_BY_GROUP_NAME: case SK_BY_GROUP_ID: if(nentry->gid != pentry->gid) return pos; break; case SK_BY_OWNER_NAME: case SK_BY_OWNER_ID: if(nentry->uid != pentry->uid) return pos; break; case SK_BY_MODE: if(nentry->mode != pentry->mode) return pos; break; case SK_BY_PERMISSIONS: { char nperms[16]; get_perm_string(nperms, sizeof(nperms), nentry->mode); if(strcmp(nperms, perms) != 0) { return pos; } break; } case SK_BY_NLINKS: if(nentry->nlinks != pentry->nlinks) { return pos; } break; #endif } /* Id sorting is builtin only and is defined outside SortingKey * enumeration. */ if((int)sorting_key == SK_BY_ID) { if(nentry->id != pentry->id) { return pos; } } } return pos; } /* Finds pointer to the beginning of the last extension of the file name. * Returns the pointer, which might point to the NUL byte if there are no * extensions. */ static const char * get_last_ext(const char name[]) { const char *const ext = strrchr(name, '.'); return (ext == NULL) ? (name + strlen(name)) : (ext + 1); } int flist_find_dir_group(const FileView *view, int next) { const int correction = next ? -1 : 0; const int lb = correction; const int ub = view->list_rows + correction; const int inc = next ? +1 : -1; int pos = curr_view->list_pos; dir_entry_t *pentry = &curr_view->dir_entry[pos]; const int is_dir = fentry_is_dir(pentry); while(pos > lb && pos < ub) { dir_entry_t *nentry; pos += inc; nentry = &curr_view->dir_entry[pos]; if(is_dir != fentry_is_dir(nentry)) { break; } } return pos; } int flist_first_sibling(const FileView *view) { const int parent = view->list_pos - view->dir_entry[view->list_pos].child_pos; return (parent == view->list_pos ? 0 : parent + 1); } int flist_last_sibling(const FileView *view) { int pos = view->list_pos - view->dir_entry[view->list_pos].child_pos; if(pos == view->list_pos) { /* For top-level entry, find the last top-level entry. */ pos = view->list_rows - 1; while(view->dir_entry[pos].child_pos != 0) { pos -= view->dir_entry[pos].child_pos; } } else { /* For non-top-level entry, go to last tree item and go up until our * child. */ const int parent = pos; pos = parent + view->dir_entry[parent].child_count; while(pos - view->dir_entry[pos].child_pos != parent) { pos -= view->dir_entry[pos].child_pos; } } return pos; }