Example #1
0
char *
prepare_targets(FileView *view)
{
	if(view->selected_files > 0)
	{
		return expand_macros("%f", NULL, NULL, 1);
	}

	if(!flist_custom_active(view))
	{
		return strdup(".");
	}

	return (vifm_chdir(flist_get_dir(view)) == 0) ? strdup(".") : NULL;
}
Example #2
0
File: sort.c Project: acklinr/vifm
void
sort_entries(view_t *v, entries_t entries)
{
	if(v->sort_g[0] > SK_LAST)
	{
		/* Completely skip sorting if primary key isn't set. */
		return;
	}

	view = v;
	view_sort = v->sort_g;
	view_sort_groups = v->sort_groups_g;
	custom_view = flist_custom_active(v);

	sort_sequence(entries.entries, entries.nentries);
}
Example #3
0
/* Clones one view into another.  Path specifies location of active pane and can
 * be NULL.  The destination view is assumed to not own any resources. */
static void
clone_view(view_t *dst, view_t *src, const char path[])
{
	strcpy(dst->curr_dir, path == NULL ? flist_get_dir(src) : path);
	dst->timestamps_mutex = src->timestamps_mutex;
	dst->win = src->win;
	dst->title = src->title;

	flist_init_view(dst);
	dst->dir_entry[0].origin = src->curr_dir;

	clone_local_options(src, dst, 1);
	matcher_free(dst->manual_filter);
	dst->manual_filter = matcher_clone(src->manual_filter);
	filter_assign(&dst->auto_filter, &src->auto_filter);
	dst->prev_invert = src->prev_invert;
	dst->invert = src->invert;

	/* Clone current entry even though we populate file list later to give
	 * reloading reference point for cursor. */
	replace_dir_entries(dst, &dst->dir_entry, &dst->list_rows,
			get_current_entry(src), 1);
	dst->list_pos = 0;
	/* Clone viewport configuration. */
	dst->curr_line = src->curr_line;
	dst->top_line = src->top_line;
	dst->window_rows = src->window_rows;
	dst->window_cols = src->window_cols;
	dst->window_cells = src->window_cells;

	flist_hist_resize(dst, cfg.history_len);
	flist_hist_clone(dst, src);
	if(path != NULL && !flist_custom_active(src))
	{
		/* Record location we're leaving. */
		flist_hist_save(dst, src->curr_dir, get_current_file_name(src),
				src->list_pos - src->top_line);
	}

	(void)populate_dir_list(dst, path == NULL);
	/* XXX: do we need to update origins or is this a leftover from before list
	 *      population was introduced? */
	flist_update_origins(dst, &dst->curr_dir[0], &src->curr_dir[0]);

	/* Record new location. */
	flist_hist_save(dst, NULL, NULL, -1);
}
Example #4
0
/* Gets string representation of file type.  Returns the string. */
static var_t
filetype_builtin(const call_info_t *call_info)
{
	char *str_val = var_to_string(call_info->argv[0]);
	const int fnum = get_fnum(str_val);
	var_val_t var_val = { .string = "" };
	free(str_val);

	if(fnum >= 0)
	{
		const FileType type = curr_view->dir_entry[fnum].type;
		var_val.const_string = get_type_str(type);
	}
	return var_new(VTYPE_STRING, var_val);
}

/* Returns file type from position or -1 if the position has wrong value. */
static int
get_fnum(const char position[])
{
	if(strcmp(position, ".") == 0)
	{
		return curr_view->list_pos;
	}
	return -1;
}

/* Retrieves type of current pane as a string. */
static var_t
getpanetype_builtin(const call_info_t *call_info)
{
	FileView *const view = curr_view;
	var_val_t var_val;

	if(flist_custom_active(view))
	{
		var_val.string = (view->custom.unsorted ? "very-custom" : "custom");
	}
	else
	{
		var_val.string = "regular";
	}

	return var_new(VTYPE_STRING, var_val);
}
Example #5
0
void
follow_file(FileView *view)
{
	if(flist_custom_active(view))
	{
		/* Entry might be freed on navigation, so make sure name and origin will
		 * remain available for the call. */
		const dir_entry_t *const entry = &view->dir_entry[view->list_pos];
		char *const name = strdup(entry->name);
		char *const origin = strdup(entry->origin);
		navigate_to_file(view, origin, name, 0);
		free(origin);
		free(name);
		return;
	}

	handle_file(view, FHE_RUN, FHL_FOLLOW);
}
Example #6
0
TSTATIC char *
append_selected_files(FileView *view, char expanded[], int under_cursor,
		int quotes, const char mod[], int for_shell)
{
	const PathType type = (view == other_view)
	                    ? PT_FULL
	                    : (flist_custom_active(view) ? PT_REL : PT_NAME);
#ifdef _WIN32
	size_t old_len = strlen(expanded);
#endif

	if(view->selected_files && !under_cursor)
	{
		int n = 0;
		dir_entry_t *entry = NULL;
		while(iter_selected_entries(view, &entry))
		{
			expanded = append_entry(view, expanded, type, entry, quotes, mod,
					for_shell);

			if(++n != view->selected_files)
			{
				expanded = append_to_expanded(expanded, " ");
			}
		}
	}
	else
	{
		expanded = append_entry(view, expanded, type, get_current_entry(view),
				quotes, mod, for_shell);
	}

#ifdef _WIN32
	if(for_shell && curr_stats.shell_type == ST_CMD)
	{
		to_back_slash(expanded + old_len);
	}
#endif

	return expanded;
}
Example #7
0
void
local_filter_apply(view_t *view, const char filter[])
{
	if(view->local_filter.in_progress)
	{
		assert(!view->local_filter.in_progress && "Wrong local filter applying.");
		return;
	}

	(void)filter_set(&view->local_filter.filter, filter);
	hists_filter_save(view->local_filter.filter.raw);

	if(flist_custom_active(view) && view->custom.type != CV_TREE &&
			view->local_filter.entry_count == 0)
	{
		/* Save unfiltered (by local filter) list for further use so it can be
		 * restored on changing local filter. */
		replace_dir_entries(view, &view->local_filter.entries,
				&view->local_filter.entry_count, view->dir_entry, view->list_rows);
	}

	ui_view_schedule_reload(view);
}
Example #8
0
/* Makes sorted by path list of entries that.  The trie is used to keep track of
 * identical files.  With non-zero dups_only, new files aren't added to the
 * trie. */
static entries_t
make_diff_list(trie_t *trie, FileView *view, int *next_id, CompareType ct,
		int skip_empty, int dups_only)
{
	int i;
	strlist_t files = {};
	entries_t r = {};
	int last_progress = 0;

	show_progress("Listing...", 0);
	if(flist_custom_active(view) &&
			ONE_OF(view->custom.type, CV_REGULAR, CV_VERY))
	{
		list_view_entries(view, &files);
	}
	else
	{
		list_files_recursively(flist_get_dir(view), view->hide_dot, &files);
	}

	show_progress("Querying...", 0);
	for(i = 0; i < files.nitems && !ui_cancellation_requested(); ++i)
	{
		char progress_msg[128];
		int progress;
		int existing_id;
		char *fingerprint;
		const char *const path = files.items[i];
		dir_entry_t *const entry = entry_list_add(view, &r.entries, &r.nentries,
				path);

		if(skip_empty && entry->size == 0)
		{
			free_dir_entry(view, entry);
			--r.nentries;
			continue;
		}

		fingerprint = get_file_fingerprint(path, entry, ct);
		/* In case we couldn't obtain fingerprint (e.g., comparing by contents and
		 * files isn't readable), ignore the file and keep going. */
		if(is_null_or_empty(fingerprint))
		{
			free(fingerprint);
			free_dir_entry(view, entry);
			--r.nentries;
			continue;
		}

		entry->tag = i;
		if(get_file_id(trie, path, fingerprint, &existing_id, ct))
		{
			entry->id = existing_id;
		}
		else if(dups_only)
		{
			entry->id = -1;
		}
		else
		{
			entry->id = *next_id;
			++*next_id;
			put_file_id(trie, path, fingerprint, entry->id, ct);
		}

		free(fingerprint);

		progress = (i*100)/files.nitems;
		if(progress != last_progress)
		{
			last_progress = progress;
			snprintf(progress_msg, sizeof(progress_msg), "Querying... %d (% 2d%%)", i,
					progress);
			show_progress(progress_msg, -1);
		}
	}

	free_string_array(files.items, files.nitems);
	return r;
}
Example #9
0
void
name_filters_add_selection(view_t *view)
{
	dir_entry_t *entry;
	filter_t filter;
	int filtered;

	(void)filter_init(&filter, FILTER_DEF_CASE_SENSITIVITY);

	/* Traverse items and update/create filter values. */
	entry = NULL;
	while(iter_selection_or_current(view, &entry))
	{
		const char *name = entry->name;
		char name_with_slash[NAME_MAX + 1 + 1];

		if(fentry_is_dir(entry))
		{
			append_slash(entry->name, name_with_slash, sizeof(name_with_slash));
			name = name_with_slash;
		}

		(void)filter_append(&view->auto_filter, name);
		(void)filter_append(&filter, name);
	}

	/* Even current file might be unavailable for filtering.  In this case, just
	 * do nothing. */
	if(filter_is_empty(&filter))
	{
		filter_dispose(&filter);
		return;
	}

	if(view->custom.type == CV_DIFF)
	{
		(void)filter_in_compare(view, &filter, &is_newly_filtered);
		ui_view_schedule_redraw(view);
		filter_dispose(&filter);
		return;
	}

	/* Update entry lists to remove entries that must be filtered out now.  No
	 * view reload is needed. */
	filtered = zap_entries(view, view->dir_entry, &view->list_rows,
			&is_newly_filtered, &filter, 0, 1);
	if(flist_custom_active(view))
	{
		(void)zap_entries(view, view->local_filter.entries,
				&view->local_filter.entry_count, &is_newly_filtered, &filter, 1, 1);
	}
	else
	{
		view->filtered += filtered;
	}

	filter_dispose(&filter);

	fpos_ensure_valid_pos(view);
	ui_view_schedule_redraw(view);
}
Example #10
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;
}