push
This commit is contained in:
217
tabexp_file.c
Normal file
217
tabexp_file.c
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright 2008-2013 Various Authors
|
||||
* Copyright 2004-2005 Timo Hirvonen
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tabexp_file.h"
|
||||
#include "tabexp.h"
|
||||
#include "load_dir.h"
|
||||
#include "misc.h"
|
||||
#include "xmalloc.h"
|
||||
#include "xstrjoin.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
static char *get_home(const char *user)
|
||||
{
|
||||
struct passwd *passwd;
|
||||
char *home;
|
||||
int len;
|
||||
|
||||
if (user[0] == 0) {
|
||||
passwd = getpwuid(getuid());
|
||||
} else {
|
||||
passwd = getpwnam(user);
|
||||
}
|
||||
if (passwd == NULL)
|
||||
return NULL;
|
||||
len = strlen(passwd->pw_dir);
|
||||
home = xnew(char, len + 2);
|
||||
memcpy(home, passwd->pw_dir, len);
|
||||
home[len] = '/';
|
||||
home[len + 1] = 0;
|
||||
return home;
|
||||
}
|
||||
|
||||
static char *get_full_dir_name(const char *dir)
|
||||
{
|
||||
char *full;
|
||||
|
||||
if (dir[0] == 0) {
|
||||
full = xstrdup("./");
|
||||
} else if (dir[0] == '~') {
|
||||
char *first_slash, *tmp, *home;
|
||||
|
||||
first_slash = strchr(dir, '/');
|
||||
tmp = xstrndup(dir, first_slash - dir);
|
||||
home = get_home(tmp + 1);
|
||||
free(tmp);
|
||||
if (home == NULL)
|
||||
return NULL;
|
||||
full = xstrjoin(home, first_slash);
|
||||
free(home);
|
||||
} else {
|
||||
full = xstrdup(dir);
|
||||
}
|
||||
return full;
|
||||
}
|
||||
|
||||
static void load_dir(struct ptr_array *array,
|
||||
const char *dirname, const char *start,
|
||||
int (*filter)(const char *, const struct stat *))
|
||||
{
|
||||
int start_len = strlen(start);
|
||||
struct directory dir;
|
||||
char *full_dir_name;
|
||||
const char *name;
|
||||
|
||||
full_dir_name = get_full_dir_name(dirname);
|
||||
if (!full_dir_name)
|
||||
return;
|
||||
|
||||
if (dir_open(&dir, full_dir_name))
|
||||
goto out;
|
||||
|
||||
while ((name = dir_read(&dir))) {
|
||||
char *str;
|
||||
|
||||
if (!start_len) {
|
||||
if (name[0] == '.')
|
||||
continue;
|
||||
} else {
|
||||
if (strncmp(name, start, start_len))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!filter(name, &dir.st))
|
||||
continue;
|
||||
|
||||
if (S_ISDIR(dir.st.st_mode)) {
|
||||
int len = strlen(name);
|
||||
|
||||
str = xnew(char, len + 2);
|
||||
memcpy(str, name, len);
|
||||
str[len++] = '/';
|
||||
str[len] = 0;
|
||||
} else {
|
||||
str = xstrdup(name);
|
||||
}
|
||||
ptr_array_add(array, str);
|
||||
}
|
||||
dir_close(&dir);
|
||||
out:
|
||||
free(full_dir_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* load all directory entries from directory 'dir' starting with 'start' and
|
||||
* filtered with 'filter'
|
||||
*/
|
||||
static void tabexp_load_dir(const char *dirname, const char *start,
|
||||
int (*filter)(const char *, const struct stat *))
|
||||
{
|
||||
PTR_ARRAY(array);
|
||||
|
||||
/* tabexp is reset */
|
||||
load_dir(&array, dirname, start, filter);
|
||||
|
||||
if (array.count) {
|
||||
ptr_array_sort(&array, strptrcmp);
|
||||
|
||||
tabexp.head = xstrdup(dirname);
|
||||
tabexp.tails = array.ptrs;
|
||||
tabexp.count = array.count;
|
||||
}
|
||||
}
|
||||
|
||||
static void tabexp_load_env_path(const char *env_path, const char *start,
|
||||
int (*filter)(const char *, const struct stat *))
|
||||
{
|
||||
char *path = xstrdup(env_path);
|
||||
PTR_ARRAY(array);
|
||||
char cwd[1024];
|
||||
char *p = path, *n;
|
||||
|
||||
/* tabexp is reset */
|
||||
do {
|
||||
n = strchr(p, ':');
|
||||
if (n)
|
||||
*n = '\0';
|
||||
if (strcmp(p, "") == 0 && getcwd(cwd, sizeof(cwd)))
|
||||
p = cwd;
|
||||
load_dir(&array, p, start, filter);
|
||||
p = n + 1;
|
||||
} while (n);
|
||||
|
||||
if (array.count) {
|
||||
ptr_array_sort(&array, strptrcoll);
|
||||
ptr_array_unique(&array, strptrcmp);
|
||||
|
||||
tabexp.head = xstrdup("");
|
||||
tabexp.tails = array.ptrs;
|
||||
tabexp.count = array.count;
|
||||
}
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
void expand_files_and_dirs(const char *src,
|
||||
int (*filter)(const char *name, const struct stat *s))
|
||||
{
|
||||
char *slash;
|
||||
|
||||
/* split src to dir and file */
|
||||
slash = strrchr(src, '/');
|
||||
if (slash) {
|
||||
char *dir;
|
||||
const char *file;
|
||||
|
||||
/* split */
|
||||
dir = xstrndup(src, slash - src + 1);
|
||||
file = slash + 1;
|
||||
/* get all dentries starting with file from dir */
|
||||
tabexp_load_dir(dir, file, filter);
|
||||
free(dir);
|
||||
} else {
|
||||
if (src[0] == '~') {
|
||||
char *home = get_home(src + 1);
|
||||
|
||||
if (home) {
|
||||
tabexp.head = xstrdup("");
|
||||
tabexp.tails = xnew(char *, 1);
|
||||
tabexp.tails[0] = home;
|
||||
tabexp.count = 1;
|
||||
}
|
||||
} else {
|
||||
tabexp_load_dir("", src, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void expand_env_path(const char *src,
|
||||
int (*filter)(const char *name, const struct stat *s))
|
||||
{
|
||||
const char *env_path = getenv("PATH");
|
||||
|
||||
if (!env_path || strcmp(env_path, "") == 0)
|
||||
return;
|
||||
|
||||
tabexp_load_env_path(env_path, src, filter);
|
||||
}
|
||||
Reference in New Issue
Block a user