зеркало из https://github.com/microsoft/git.git
Merge branch 'bw/pathspec-cleanup'
Code clean-up in the pathspec API. * bw/pathspec-cleanup: pathspec: rename prefix_pathspec to init_pathspec_item pathspec: small readability changes pathspec: create strip submodule slash helpers pathspec: create parse_element_magic helper pathspec: create parse_long_magic function pathspec: create parse_short_magic function pathspec: factor global magic into its own function pathspec: simpler logic to prefix original pathspec elements pathspec: always show mnemonic and name in unsupported_magic pathspec: remove unused variable from unsupported_magic pathspec: copy and free owned memory pathspec: remove the deprecated get_pathspec function ls-tree: convert show_recursive to use the pathspec struct interface dir: convert fill_directory to use the pathspec struct interface dir: remove struct path_simplify mv: remove use of deprecated 'get_pathspec()'
This commit is contained in:
Коммит
fe9ec8bdf6
|
@ -27,8 +27,6 @@ parse_pathspec(). This function takes several arguments:
|
|||
|
||||
- prefix and args come from cmd_* functions
|
||||
|
||||
get_pathspec() is obsolete and should never be used in new code.
|
||||
|
||||
parse_pathspec() helps catch unsupported features and reject them
|
||||
politely. At a lower level, different pathspec-related functions may
|
||||
not support the same set of features. Such pathspec-sensitive
|
||||
|
|
|
@ -31,21 +31,18 @@ static const char * const ls_tree_usage[] = {
|
|||
|
||||
static int show_recursive(const char *base, int baselen, const char *pathname)
|
||||
{
|
||||
const char **s;
|
||||
int i;
|
||||
|
||||
if (ls_options & LS_RECURSIVE)
|
||||
return 1;
|
||||
|
||||
s = pathspec._raw;
|
||||
if (!s)
|
||||
if (!pathspec.nr)
|
||||
return 0;
|
||||
|
||||
for (;;) {
|
||||
const char *spec = *s++;
|
||||
for (i = 0; i < pathspec.nr; i++) {
|
||||
const char *spec = pathspec.items[i].match;
|
||||
int len, speclen;
|
||||
|
||||
if (!spec)
|
||||
return 0;
|
||||
if (strncmp(base, spec, baselen))
|
||||
continue;
|
||||
len = strlen(pathname);
|
||||
|
@ -59,6 +56,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
|
|||
continue;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int show_tree(const unsigned char *sha1, struct strbuf *base,
|
||||
|
@ -175,8 +173,8 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
|
|||
* cannot be lifted until it is converted to use
|
||||
* match_pathspec() or tree_entry_interesting()
|
||||
*/
|
||||
parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |
|
||||
PATHSPEC_EXCLUDE,
|
||||
parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &
|
||||
~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
|
||||
PATHSPEC_PREFER_CWD,
|
||||
prefix, argv + 1);
|
||||
for (i = 0; i < pathspec.nr; i++)
|
||||
|
|
50
builtin/mv.c
50
builtin/mv.c
|
@ -4,6 +4,7 @@
|
|||
* Copyright (C) 2006 Johannes Schindelin
|
||||
*/
|
||||
#include "builtin.h"
|
||||
#include "pathspec.h"
|
||||
#include "lockfile.h"
|
||||
#include "dir.h"
|
||||
#include "cache-tree.h"
|
||||
|
@ -19,31 +20,42 @@ static const char * const builtin_mv_usage[] = {
|
|||
#define DUP_BASENAME 1
|
||||
#define KEEP_TRAILING_SLASH 2
|
||||
|
||||
static const char **internal_copy_pathspec(const char *prefix,
|
||||
const char **pathspec,
|
||||
int count, unsigned flags)
|
||||
static const char **internal_prefix_pathspec(const char *prefix,
|
||||
const char **pathspec,
|
||||
int count, unsigned flags)
|
||||
{
|
||||
int i;
|
||||
const char **result;
|
||||
int prefixlen = prefix ? strlen(prefix) : 0;
|
||||
ALLOC_ARRAY(result, count + 1);
|
||||
COPY_ARRAY(result, pathspec, count);
|
||||
result[count] = NULL;
|
||||
|
||||
/* Create an intermediate copy of the pathspec based on the flags */
|
||||
for (i = 0; i < count; i++) {
|
||||
int length = strlen(result[i]);
|
||||
int length = strlen(pathspec[i]);
|
||||
int to_copy = length;
|
||||
char *it;
|
||||
while (!(flags & KEEP_TRAILING_SLASH) &&
|
||||
to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
|
||||
to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))
|
||||
to_copy--;
|
||||
if (to_copy != length || flags & DUP_BASENAME) {
|
||||
char *it = xmemdupz(result[i], to_copy);
|
||||
if (flags & DUP_BASENAME) {
|
||||
result[i] = xstrdup(basename(it));
|
||||
free(it);
|
||||
} else
|
||||
result[i] = it;
|
||||
|
||||
it = xmemdupz(pathspec[i], to_copy);
|
||||
if (flags & DUP_BASENAME) {
|
||||
result[i] = xstrdup(basename(it));
|
||||
free(it);
|
||||
} else {
|
||||
result[i] = it;
|
||||
}
|
||||
}
|
||||
return get_pathspec(prefix, result);
|
||||
result[count] = NULL;
|
||||
|
||||
/* Prefix the pathspec and free the old intermediate strings */
|
||||
for (i = 0; i < count; i++) {
|
||||
const char *match = prefix_path(prefix, prefixlen, result[i]);
|
||||
free((char *) result[i]);
|
||||
result[i] = match;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char *add_slash(const char *path)
|
||||
|
@ -130,7 +142,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
|||
if (read_cache() < 0)
|
||||
die(_("index file corrupt"));
|
||||
|
||||
source = internal_copy_pathspec(prefix, argv, argc, 0);
|
||||
source = internal_prefix_pathspec(prefix, argv, argc, 0);
|
||||
modes = xcalloc(argc, sizeof(enum update_mode));
|
||||
/*
|
||||
* Keep trailing slash, needed to let
|
||||
|
@ -140,16 +152,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
|||
flags = KEEP_TRAILING_SLASH;
|
||||
if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
|
||||
flags = 0;
|
||||
dest_path = internal_copy_pathspec(prefix, argv + argc, 1, flags);
|
||||
dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);
|
||||
submodule_gitfile = xcalloc(argc, sizeof(char *));
|
||||
|
||||
if (dest_path[0][0] == '\0')
|
||||
/* special case: "." was normalized to "" */
|
||||
destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
|
||||
destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
|
||||
else if (!lstat(dest_path[0], &st) &&
|
||||
S_ISDIR(st.st_mode)) {
|
||||
dest_path[0] = add_slash(dest_path[0]);
|
||||
destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
|
||||
destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
|
||||
} else {
|
||||
if (argc != 1)
|
||||
die(_("destination '%s' is not a directory"), dest_path[0]);
|
||||
|
|
1
cache.h
1
cache.h
|
@ -514,7 +514,6 @@ extern void set_git_work_tree(const char *tree);
|
|||
|
||||
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
|
||||
|
||||
extern const char **get_pathspec(const char *prefix, const char **pathspec);
|
||||
extern void setup_work_tree(void);
|
||||
extern const char *setup_git_directory_gently(int *);
|
||||
extern const char *setup_git_directory(void);
|
||||
|
|
189
dir.c
189
dir.c
|
@ -16,11 +16,6 @@
|
|||
#include "varint.h"
|
||||
#include "ewah/ewok.h"
|
||||
|
||||
struct path_simplify {
|
||||
int len;
|
||||
const char *path;
|
||||
};
|
||||
|
||||
/*
|
||||
* Tells read_directory_recursive how a file or directory should be treated.
|
||||
* Values are ordered by significance, e.g. if a directory contains both
|
||||
|
@ -50,7 +45,7 @@ struct cached_dir {
|
|||
|
||||
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
||||
const char *path, int len, struct untracked_cache_dir *untracked,
|
||||
int check_only, const struct path_simplify *simplify);
|
||||
int check_only, const struct pathspec *pathspec);
|
||||
static int get_dtype(struct dirent *de, const char *path, int len);
|
||||
|
||||
int fspathcmp(const char *a, const char *b)
|
||||
|
@ -179,17 +174,21 @@ char *common_prefix(const struct pathspec *pathspec)
|
|||
|
||||
int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
|
||||
{
|
||||
size_t len;
|
||||
char *prefix;
|
||||
size_t prefix_len;
|
||||
|
||||
/*
|
||||
* Calculate common prefix for the pathspec, and
|
||||
* use that to optimize the directory walk
|
||||
*/
|
||||
len = common_prefix_len(pathspec);
|
||||
prefix = common_prefix(pathspec);
|
||||
prefix_len = prefix ? strlen(prefix) : 0;
|
||||
|
||||
/* Read the directory and prune it */
|
||||
read_directory(dir, pathspec->nr ? pathspec->_raw[0] : "", len, pathspec);
|
||||
return len;
|
||||
read_directory(dir, prefix, prefix_len, pathspec);
|
||||
|
||||
free(prefix);
|
||||
return prefix_len;
|
||||
}
|
||||
|
||||
int within_depth(const char *name, int namelen,
|
||||
|
@ -1312,7 +1311,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
|
|||
static enum path_treatment treat_directory(struct dir_struct *dir,
|
||||
struct untracked_cache_dir *untracked,
|
||||
const char *dirname, int len, int baselen, int exclude,
|
||||
const struct path_simplify *simplify)
|
||||
const struct pathspec *pathspec)
|
||||
{
|
||||
/* The "len-1" is to strip the final '/' */
|
||||
switch (directory_exists_in_index(dirname, len-1)) {
|
||||
|
@ -1341,7 +1340,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
|
|||
untracked = lookup_untracked(dir->untracked, untracked,
|
||||
dirname + baselen, len - baselen);
|
||||
return read_directory_recursive(dir, dirname, len,
|
||||
untracked, 1, simplify);
|
||||
untracked, 1, pathspec);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1349,24 +1348,33 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
|
|||
* reading - if the path cannot possibly be in the pathspec,
|
||||
* return true, and we'll skip it early.
|
||||
*/
|
||||
static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify)
|
||||
static int simplify_away(const char *path, int pathlen,
|
||||
const struct pathspec *pathspec)
|
||||
{
|
||||
if (simplify) {
|
||||
for (;;) {
|
||||
const char *match = simplify->path;
|
||||
int len = simplify->len;
|
||||
int i;
|
||||
|
||||
if (!match)
|
||||
break;
|
||||
if (len > pathlen)
|
||||
len = pathlen;
|
||||
if (!memcmp(path, match, len))
|
||||
return 0;
|
||||
simplify++;
|
||||
}
|
||||
return 1;
|
||||
if (!pathspec || !pathspec->nr)
|
||||
return 0;
|
||||
|
||||
GUARD_PATHSPEC(pathspec,
|
||||
PATHSPEC_FROMTOP |
|
||||
PATHSPEC_MAXDEPTH |
|
||||
PATHSPEC_LITERAL |
|
||||
PATHSPEC_GLOB |
|
||||
PATHSPEC_ICASE |
|
||||
PATHSPEC_EXCLUDE);
|
||||
|
||||
for (i = 0; i < pathspec->nr; i++) {
|
||||
const struct pathspec_item *item = &pathspec->items[i];
|
||||
int len = item->nowildcard_len;
|
||||
|
||||
if (len > pathlen)
|
||||
len = pathlen;
|
||||
if (!ps_strncmp(item, item->match, path, len))
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1380,19 +1388,33 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli
|
|||
* 2. the path is a directory prefix of some element in the
|
||||
* pathspec
|
||||
*/
|
||||
static int exclude_matches_pathspec(const char *path, int len,
|
||||
const struct path_simplify *simplify)
|
||||
static int exclude_matches_pathspec(const char *path, int pathlen,
|
||||
const struct pathspec *pathspec)
|
||||
{
|
||||
if (simplify) {
|
||||
for (; simplify->path; simplify++) {
|
||||
if (len == simplify->len
|
||||
&& !memcmp(path, simplify->path, len))
|
||||
return 1;
|
||||
if (len < simplify->len
|
||||
&& simplify->path[len] == '/'
|
||||
&& !memcmp(path, simplify->path, len))
|
||||
return 1;
|
||||
}
|
||||
int i;
|
||||
|
||||
if (!pathspec || !pathspec->nr)
|
||||
return 0;
|
||||
|
||||
GUARD_PATHSPEC(pathspec,
|
||||
PATHSPEC_FROMTOP |
|
||||
PATHSPEC_MAXDEPTH |
|
||||
PATHSPEC_LITERAL |
|
||||
PATHSPEC_GLOB |
|
||||
PATHSPEC_ICASE |
|
||||
PATHSPEC_EXCLUDE);
|
||||
|
||||
for (i = 0; i < pathspec->nr; i++) {
|
||||
const struct pathspec_item *item = &pathspec->items[i];
|
||||
int len = item->nowildcard_len;
|
||||
|
||||
if (len == pathlen &&
|
||||
!ps_strncmp(item, item->match, path, pathlen))
|
||||
return 1;
|
||||
if (len > pathlen &&
|
||||
item->match[pathlen] == '/' &&
|
||||
!ps_strncmp(item, item->match, path, pathlen))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1460,7 +1482,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
|
|||
struct untracked_cache_dir *untracked,
|
||||
struct strbuf *path,
|
||||
int baselen,
|
||||
const struct path_simplify *simplify,
|
||||
const struct pathspec *pathspec,
|
||||
int dtype, struct dirent *de)
|
||||
{
|
||||
int exclude;
|
||||
|
@ -1512,7 +1534,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
|
|||
case DT_DIR:
|
||||
strbuf_addch(path, '/');
|
||||
return treat_directory(dir, untracked, path->buf, path->len,
|
||||
baselen, exclude, simplify);
|
||||
baselen, exclude, pathspec);
|
||||
case DT_REG:
|
||||
case DT_LNK:
|
||||
return exclude ? path_excluded : path_untracked;
|
||||
|
@ -1524,7 +1546,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,
|
|||
struct cached_dir *cdir,
|
||||
struct strbuf *path,
|
||||
int baselen,
|
||||
const struct path_simplify *simplify)
|
||||
const struct pathspec *pathspec)
|
||||
{
|
||||
strbuf_setlen(path, baselen);
|
||||
if (!cdir->ucd) {
|
||||
|
@ -1541,7 +1563,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,
|
|||
* with check_only set.
|
||||
*/
|
||||
return read_directory_recursive(dir, path->buf, path->len,
|
||||
cdir->ucd, 1, simplify);
|
||||
cdir->ucd, 1, pathspec);
|
||||
/*
|
||||
* We get path_recurse in the first run when
|
||||
* directory_exists_in_index() returns index_nonexistent. We
|
||||
|
@ -1556,23 +1578,23 @@ static enum path_treatment treat_path(struct dir_struct *dir,
|
|||
struct cached_dir *cdir,
|
||||
struct strbuf *path,
|
||||
int baselen,
|
||||
const struct path_simplify *simplify)
|
||||
const struct pathspec *pathspec)
|
||||
{
|
||||
int dtype;
|
||||
struct dirent *de = cdir->de;
|
||||
|
||||
if (!de)
|
||||
return treat_path_fast(dir, untracked, cdir, path,
|
||||
baselen, simplify);
|
||||
baselen, pathspec);
|
||||
if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
|
||||
return path_none;
|
||||
strbuf_setlen(path, baselen);
|
||||
strbuf_addstr(path, de->d_name);
|
||||
if (simplify_away(path->buf, path->len, simplify))
|
||||
if (simplify_away(path->buf, path->len, pathspec))
|
||||
return path_none;
|
||||
|
||||
dtype = DTYPE(de);
|
||||
return treat_one_path(dir, untracked, path, baselen, simplify, dtype, de);
|
||||
return treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);
|
||||
}
|
||||
|
||||
static void add_untracked(struct untracked_cache_dir *dir, const char *name)
|
||||
|
@ -1703,7 +1725,7 @@ static void close_cached_dir(struct cached_dir *cdir)
|
|||
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
||||
const char *base, int baselen,
|
||||
struct untracked_cache_dir *untracked, int check_only,
|
||||
const struct path_simplify *simplify)
|
||||
const struct pathspec *pathspec)
|
||||
{
|
||||
struct cached_dir cdir;
|
||||
enum path_treatment state, subdir_state, dir_state = path_none;
|
||||
|
@ -1719,7 +1741,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
|||
|
||||
while (!read_cached_dir(&cdir)) {
|
||||
/* check how the file or directory should be treated */
|
||||
state = treat_path(dir, untracked, &cdir, &path, baselen, simplify);
|
||||
state = treat_path(dir, untracked, &cdir, &path,
|
||||
baselen, pathspec);
|
||||
|
||||
if (state > dir_state)
|
||||
dir_state = state;
|
||||
|
@ -1731,8 +1754,9 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
|||
path.buf + baselen,
|
||||
path.len - baselen);
|
||||
subdir_state =
|
||||
read_directory_recursive(dir, path.buf, path.len,
|
||||
ud, check_only, simplify);
|
||||
read_directory_recursive(dir, path.buf,
|
||||
path.len, ud,
|
||||
check_only, pathspec);
|
||||
if (subdir_state > dir_state)
|
||||
dir_state = subdir_state;
|
||||
}
|
||||
|
@ -1756,7 +1780,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
|||
else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
|
||||
((dir->flags & DIR_COLLECT_IGNORED) &&
|
||||
exclude_matches_pathspec(path.buf, path.len,
|
||||
simplify)))
|
||||
pathspec)))
|
||||
dir_add_ignored(dir, path.buf, path.len);
|
||||
break;
|
||||
|
||||
|
@ -1787,36 +1811,9 @@ static int cmp_name(const void *p1, const void *p2)
|
|||
return name_compare(e1->name, e1->len, e2->name, e2->len);
|
||||
}
|
||||
|
||||
static struct path_simplify *create_simplify(const char **pathspec)
|
||||
{
|
||||
int nr, alloc = 0;
|
||||
struct path_simplify *simplify = NULL;
|
||||
|
||||
if (!pathspec)
|
||||
return NULL;
|
||||
|
||||
for (nr = 0 ; ; nr++) {
|
||||
const char *match;
|
||||
ALLOC_GROW(simplify, nr + 1, alloc);
|
||||
match = *pathspec++;
|
||||
if (!match)
|
||||
break;
|
||||
simplify[nr].path = match;
|
||||
simplify[nr].len = simple_length(match);
|
||||
}
|
||||
simplify[nr].path = NULL;
|
||||
simplify[nr].len = 0;
|
||||
return simplify;
|
||||
}
|
||||
|
||||
static void free_simplify(struct path_simplify *simplify)
|
||||
{
|
||||
free(simplify);
|
||||
}
|
||||
|
||||
static int treat_leading_path(struct dir_struct *dir,
|
||||
const char *path, int len,
|
||||
const struct path_simplify *simplify)
|
||||
const struct pathspec *pathspec)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
int baselen, rc = 0;
|
||||
|
@ -1840,9 +1837,9 @@ static int treat_leading_path(struct dir_struct *dir,
|
|||
strbuf_add(&sb, path, baselen);
|
||||
if (!is_directory(sb.buf))
|
||||
break;
|
||||
if (simplify_away(sb.buf, sb.len, simplify))
|
||||
if (simplify_away(sb.buf, sb.len, pathspec))
|
||||
break;
|
||||
if (treat_one_path(dir, NULL, &sb, baselen, simplify,
|
||||
if (treat_one_path(dir, NULL, &sb, baselen, pathspec,
|
||||
DT_DIR, NULL) == path_none)
|
||||
break; /* do not recurse into it */
|
||||
if (len <= baselen) {
|
||||
|
@ -2010,33 +2007,14 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
|
|||
return root;
|
||||
}
|
||||
|
||||
int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)
|
||||
int read_directory(struct dir_struct *dir, const char *path,
|
||||
int len, const struct pathspec *pathspec)
|
||||
{
|
||||
struct path_simplify *simplify;
|
||||
struct untracked_cache_dir *untracked;
|
||||
|
||||
/*
|
||||
* Check out create_simplify()
|
||||
*/
|
||||
if (pathspec)
|
||||
GUARD_PATHSPEC(pathspec,
|
||||
PATHSPEC_FROMTOP |
|
||||
PATHSPEC_MAXDEPTH |
|
||||
PATHSPEC_LITERAL |
|
||||
PATHSPEC_GLOB |
|
||||
PATHSPEC_ICASE |
|
||||
PATHSPEC_EXCLUDE);
|
||||
|
||||
if (has_symlink_leading_path(path, len))
|
||||
return dir->nr;
|
||||
|
||||
/*
|
||||
* exclude patterns are treated like positive ones in
|
||||
* create_simplify. Usually exclude patterns should be a
|
||||
* subset of positive ones, which has no impacts on
|
||||
* create_simplify().
|
||||
*/
|
||||
simplify = create_simplify(pathspec ? pathspec->_raw : NULL);
|
||||
untracked = validate_untracked_cache(dir, len, pathspec);
|
||||
if (!untracked)
|
||||
/*
|
||||
|
@ -2044,9 +2022,8 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
|
|||
* e.g. prep_exclude()
|
||||
*/
|
||||
dir->untracked = NULL;
|
||||
if (!len || treat_leading_path(dir, path, len, simplify))
|
||||
read_directory_recursive(dir, path, len, untracked, 0, simplify);
|
||||
free_simplify(simplify);
|
||||
if (!len || treat_leading_path(dir, path, len, pathspec))
|
||||
read_directory_recursive(dir, path, len, untracked, 0, pathspec);
|
||||
QSORT(dir->entries, dir->nr, cmp_name);
|
||||
QSORT(dir->ignored, dir->ignored_nr, cmp_name);
|
||||
if (dir->untracked) {
|
||||
|
|
494
pathspec.c
494
pathspec.c
|
@ -67,20 +67,19 @@ static struct pathspec_magic {
|
|||
char mnemonic; /* this cannot be ':'! */
|
||||
const char *name;
|
||||
} pathspec_magic[] = {
|
||||
{ PATHSPEC_FROMTOP, '/', "top" },
|
||||
{ PATHSPEC_LITERAL, 0, "literal" },
|
||||
{ PATHSPEC_GLOB, '\0', "glob" },
|
||||
{ PATHSPEC_ICASE, '\0', "icase" },
|
||||
{ PATHSPEC_EXCLUDE, '!', "exclude" },
|
||||
{ PATHSPEC_FROMTOP, '/', "top" },
|
||||
{ PATHSPEC_LITERAL, '\0', "literal" },
|
||||
{ PATHSPEC_GLOB, '\0', "glob" },
|
||||
{ PATHSPEC_ICASE, '\0', "icase" },
|
||||
{ PATHSPEC_EXCLUDE, '!', "exclude" },
|
||||
};
|
||||
|
||||
static void prefix_short_magic(struct strbuf *sb, int prefixlen,
|
||||
unsigned short_magic)
|
||||
static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)
|
||||
{
|
||||
int i;
|
||||
strbuf_addstr(sb, ":(");
|
||||
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
|
||||
if (short_magic & pathspec_magic[i].bit) {
|
||||
if (magic & pathspec_magic[i].bit) {
|
||||
if (sb->buf[sb->len - 1] != '(')
|
||||
strbuf_addch(sb, ',');
|
||||
strbuf_addstr(sb, pathspec_magic[i].name);
|
||||
|
@ -88,54 +87,61 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,
|
|||
strbuf_addf(sb, ",prefix:%d)", prefixlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Take an element of a pathspec and check for magic signatures.
|
||||
* Append the result to the prefix. Return the magic bitmap.
|
||||
*
|
||||
* For now, we only parse the syntax and throw out anything other than
|
||||
* "top" magic.
|
||||
*
|
||||
* NEEDSWORK: This needs to be rewritten when we start migrating
|
||||
* get_pathspec() users to use the "struct pathspec" interface. For
|
||||
* example, a pathspec element may be marked as case-insensitive, but
|
||||
* the prefix part must always match literally, and a single stupid
|
||||
* string cannot express such a case.
|
||||
*/
|
||||
static unsigned prefix_pathspec(struct pathspec_item *item,
|
||||
unsigned *p_short_magic,
|
||||
const char **raw, unsigned flags,
|
||||
const char *prefix, int prefixlen,
|
||||
const char *elt)
|
||||
static inline int get_literal_global(void)
|
||||
{
|
||||
static int literal_global = -1;
|
||||
static int glob_global = -1;
|
||||
static int noglob_global = -1;
|
||||
static int icase_global = -1;
|
||||
unsigned magic = 0, short_magic = 0, global_magic = 0;
|
||||
const char *copyfrom = elt, *long_magic_end = NULL;
|
||||
char *match;
|
||||
int i, pathspec_prefix = -1;
|
||||
static int literal = -1;
|
||||
|
||||
if (literal_global < 0)
|
||||
literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
|
||||
if (literal_global)
|
||||
if (literal < 0)
|
||||
literal = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
|
||||
|
||||
return literal;
|
||||
}
|
||||
|
||||
static inline int get_glob_global(void)
|
||||
{
|
||||
static int glob = -1;
|
||||
|
||||
if (glob < 0)
|
||||
glob = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);
|
||||
|
||||
return glob;
|
||||
}
|
||||
|
||||
static inline int get_noglob_global(void)
|
||||
{
|
||||
static int noglob = -1;
|
||||
|
||||
if (noglob < 0)
|
||||
noglob = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);
|
||||
|
||||
return noglob;
|
||||
}
|
||||
|
||||
static inline int get_icase_global(void)
|
||||
{
|
||||
static int icase = -1;
|
||||
|
||||
if (icase < 0)
|
||||
icase = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);
|
||||
|
||||
return icase;
|
||||
}
|
||||
|
||||
static int get_global_magic(int element_magic)
|
||||
{
|
||||
int global_magic = 0;
|
||||
|
||||
if (get_literal_global())
|
||||
global_magic |= PATHSPEC_LITERAL;
|
||||
|
||||
if (glob_global < 0)
|
||||
glob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);
|
||||
if (glob_global)
|
||||
/* --glob-pathspec is overridden by :(literal) */
|
||||
if (get_glob_global() && !(element_magic & PATHSPEC_LITERAL))
|
||||
global_magic |= PATHSPEC_GLOB;
|
||||
|
||||
if (noglob_global < 0)
|
||||
noglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);
|
||||
|
||||
if (glob_global && noglob_global)
|
||||
if (get_glob_global() && get_noglob_global())
|
||||
die(_("global 'glob' and 'noglob' pathspec settings are incompatible"));
|
||||
|
||||
|
||||
if (icase_global < 0)
|
||||
icase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);
|
||||
if (icase_global)
|
||||
if (get_icase_global())
|
||||
global_magic |= PATHSPEC_ICASE;
|
||||
|
||||
if ((global_magic & PATHSPEC_LITERAL) &&
|
||||
|
@ -143,84 +149,177 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||
die(_("global 'literal' pathspec setting is incompatible "
|
||||
"with all other global pathspec settings"));
|
||||
|
||||
if (flags & PATHSPEC_LITERAL_PATH)
|
||||
global_magic = 0;
|
||||
|
||||
if (elt[0] != ':' || literal_global ||
|
||||
(flags & PATHSPEC_LITERAL_PATH)) {
|
||||
; /* nothing to do */
|
||||
} else if (elt[1] == '(') {
|
||||
/* longhand */
|
||||
const char *nextat;
|
||||
for (copyfrom = elt + 2;
|
||||
*copyfrom && *copyfrom != ')';
|
||||
copyfrom = nextat) {
|
||||
size_t len = strcspn(copyfrom, ",)");
|
||||
if (copyfrom[len] == ',')
|
||||
nextat = copyfrom + len + 1;
|
||||
else
|
||||
/* handle ')' and '\0' */
|
||||
nextat = copyfrom + len;
|
||||
if (!len)
|
||||
continue;
|
||||
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
|
||||
if (strlen(pathspec_magic[i].name) == len &&
|
||||
!strncmp(pathspec_magic[i].name, copyfrom, len)) {
|
||||
magic |= pathspec_magic[i].bit;
|
||||
break;
|
||||
}
|
||||
if (starts_with(copyfrom, "prefix:")) {
|
||||
char *endptr;
|
||||
pathspec_prefix = strtol(copyfrom + 7,
|
||||
&endptr, 10);
|
||||
if (endptr - copyfrom != len)
|
||||
die(_("invalid parameter for pathspec magic 'prefix'"));
|
||||
/* "i" would be wrong, but it does not matter */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ARRAY_SIZE(pathspec_magic) <= i)
|
||||
die(_("Invalid pathspec magic '%.*s' in '%s'"),
|
||||
(int) len, copyfrom, elt);
|
||||
}
|
||||
if (*copyfrom != ')')
|
||||
die(_("Missing ')' at the end of pathspec magic in '%s'"), elt);
|
||||
long_magic_end = copyfrom;
|
||||
copyfrom++;
|
||||
} else {
|
||||
/* shorthand */
|
||||
for (copyfrom = elt + 1;
|
||||
*copyfrom && *copyfrom != ':';
|
||||
copyfrom++) {
|
||||
char ch = *copyfrom;
|
||||
|
||||
if (!is_pathspec_magic(ch))
|
||||
break;
|
||||
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
|
||||
if (pathspec_magic[i].mnemonic == ch) {
|
||||
short_magic |= pathspec_magic[i].bit;
|
||||
break;
|
||||
}
|
||||
if (ARRAY_SIZE(pathspec_magic) <= i)
|
||||
die(_("Unimplemented pathspec magic '%c' in '%s'"),
|
||||
ch, elt);
|
||||
}
|
||||
if (*copyfrom == ':')
|
||||
copyfrom++;
|
||||
}
|
||||
|
||||
magic |= short_magic;
|
||||
*p_short_magic = short_magic;
|
||||
|
||||
/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */
|
||||
if (noglob_global && !(magic & PATHSPEC_GLOB))
|
||||
if (get_noglob_global() && !(element_magic & PATHSPEC_GLOB))
|
||||
global_magic |= PATHSPEC_LITERAL;
|
||||
|
||||
/* --glob-pathspec is overridden by :(literal) */
|
||||
if ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))
|
||||
global_magic &= ~PATHSPEC_GLOB;
|
||||
return global_magic;
|
||||
}
|
||||
|
||||
magic |= global_magic;
|
||||
/*
|
||||
* Parse the pathspec element looking for long magic
|
||||
*
|
||||
* saves all magic in 'magic'
|
||||
* if prefix magic is used, save the prefix length in 'prefix_len'
|
||||
* returns the position in 'elem' after all magic has been parsed
|
||||
*/
|
||||
static const char *parse_long_magic(unsigned *magic, int *prefix_len,
|
||||
const char *elem)
|
||||
{
|
||||
const char *pos;
|
||||
const char *nextat;
|
||||
|
||||
for (pos = elem + 2; *pos && *pos != ')'; pos = nextat) {
|
||||
size_t len = strcspn(pos, ",)");
|
||||
int i;
|
||||
|
||||
if (pos[len] == ',')
|
||||
nextat = pos + len + 1; /* handle ',' */
|
||||
else
|
||||
nextat = pos + len; /* handle ')' and '\0' */
|
||||
|
||||
if (!len)
|
||||
continue;
|
||||
|
||||
if (starts_with(pos, "prefix:")) {
|
||||
char *endptr;
|
||||
*prefix_len = strtol(pos + 7, &endptr, 10);
|
||||
if (endptr - pos != len)
|
||||
die(_("invalid parameter for pathspec magic 'prefix'"));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
|
||||
if (strlen(pathspec_magic[i].name) == len &&
|
||||
!strncmp(pathspec_magic[i].name, pos, len)) {
|
||||
*magic |= pathspec_magic[i].bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ARRAY_SIZE(pathspec_magic) <= i)
|
||||
die(_("Invalid pathspec magic '%.*s' in '%s'"),
|
||||
(int) len, pos, elem);
|
||||
}
|
||||
|
||||
if (*pos != ')')
|
||||
die(_("Missing ')' at the end of pathspec magic in '%s'"),
|
||||
elem);
|
||||
pos++;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the pathspec element looking for short magic
|
||||
*
|
||||
* saves all magic in 'magic'
|
||||
* returns the position in 'elem' after all magic has been parsed
|
||||
*/
|
||||
static const char *parse_short_magic(unsigned *magic, const char *elem)
|
||||
{
|
||||
const char *pos;
|
||||
|
||||
for (pos = elem + 1; *pos && *pos != ':'; pos++) {
|
||||
char ch = *pos;
|
||||
int i;
|
||||
|
||||
if (!is_pathspec_magic(ch))
|
||||
break;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
|
||||
if (pathspec_magic[i].mnemonic == ch) {
|
||||
*magic |= pathspec_magic[i].bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ARRAY_SIZE(pathspec_magic) <= i)
|
||||
die(_("Unimplemented pathspec magic '%c' in '%s'"),
|
||||
ch, elem);
|
||||
}
|
||||
|
||||
if (*pos == ':')
|
||||
pos++;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static const char *parse_element_magic(unsigned *magic, int *prefix_len,
|
||||
const char *elem)
|
||||
{
|
||||
if (elem[0] != ':' || get_literal_global())
|
||||
return elem; /* nothing to do */
|
||||
else if (elem[1] == '(')
|
||||
/* longhand */
|
||||
return parse_long_magic(magic, prefix_len, elem);
|
||||
else
|
||||
/* shorthand */
|
||||
return parse_short_magic(magic, elem);
|
||||
}
|
||||
|
||||
static void strip_submodule_slash_cheap(struct pathspec_item *item)
|
||||
{
|
||||
if (item->len >= 1 && item->match[item->len - 1] == '/') {
|
||||
int i = cache_name_pos(item->match, item->len - 1);
|
||||
|
||||
if (i >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) {
|
||||
item->len--;
|
||||
item->match[item->len] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void strip_submodule_slash_expensive(struct pathspec_item *item)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
int ce_len = ce_namelen(ce);
|
||||
|
||||
if (!S_ISGITLINK(ce->ce_mode))
|
||||
continue;
|
||||
|
||||
if (item->len <= ce_len || item->match[ce_len] != '/' ||
|
||||
memcmp(ce->name, item->match, ce_len))
|
||||
continue;
|
||||
|
||||
if (item->len == ce_len + 1) {
|
||||
/* strip trailing slash */
|
||||
item->len--;
|
||||
item->match[item->len] = '\0';
|
||||
} else {
|
||||
die(_("Pathspec '%s' is in submodule '%.*s'"),
|
||||
item->original, ce_len, ce->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the initialization of a pathspec_item based on a pathspec element.
|
||||
*/
|
||||
static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
|
||||
const char *prefix, int prefixlen,
|
||||
const char *elt)
|
||||
{
|
||||
unsigned magic = 0, element_magic = 0;
|
||||
const char *copyfrom = elt;
|
||||
char *match;
|
||||
int pathspec_prefix = -1;
|
||||
|
||||
/* PATHSPEC_LITERAL_PATH ignores magic */
|
||||
if (flags & PATHSPEC_LITERAL_PATH) {
|
||||
magic = PATHSPEC_LITERAL;
|
||||
} else {
|
||||
copyfrom = parse_element_magic(&element_magic,
|
||||
&pathspec_prefix,
|
||||
elt);
|
||||
magic |= element_magic;
|
||||
magic |= get_global_magic(element_magic);
|
||||
}
|
||||
|
||||
item->magic = magic;
|
||||
|
||||
if (pathspec_prefix >= 0 &&
|
||||
(prefixlen || (prefix && *prefix)))
|
||||
|
@ -229,6 +328,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||
if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))
|
||||
die(_("%s: 'literal' and 'glob' are incompatible"), elt);
|
||||
|
||||
/* Create match string which will be used for pathspec matching */
|
||||
if (pathspec_prefix >= 0) {
|
||||
match = xstrdup(copyfrom);
|
||||
prefixlen = pathspec_prefix;
|
||||
|
@ -236,69 +336,47 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||
match = xstrdup(copyfrom);
|
||||
prefixlen = 0;
|
||||
} else {
|
||||
match = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);
|
||||
match = prefix_path_gently(prefix, prefixlen,
|
||||
&prefixlen, copyfrom);
|
||||
if (!match)
|
||||
die(_("%s: '%s' is outside repository"), elt, copyfrom);
|
||||
}
|
||||
*raw = item->match = match;
|
||||
|
||||
item->match = match;
|
||||
item->len = strlen(item->match);
|
||||
item->prefix = prefixlen;
|
||||
|
||||
/*
|
||||
* Prefix the pathspec (keep all magic) and assign to
|
||||
* original. Useful for passing to another command.
|
||||
*/
|
||||
if (flags & PATHSPEC_PREFIX_ORIGIN) {
|
||||
if ((flags & PATHSPEC_PREFIX_ORIGIN) &&
|
||||
prefixlen && !get_literal_global()) {
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
if (prefixlen && !literal_global) {
|
||||
/* Preserve the actual prefix length of each pattern */
|
||||
if (short_magic)
|
||||
prefix_short_magic(&sb, prefixlen, short_magic);
|
||||
else if (long_magic_end) {
|
||||
strbuf_add(&sb, elt, long_magic_end - elt);
|
||||
strbuf_addf(&sb, ",prefix:%d)", prefixlen);
|
||||
} else
|
||||
strbuf_addf(&sb, ":(prefix:%d)", prefixlen);
|
||||
}
|
||||
|
||||
/* Preserve the actual prefix length of each pattern */
|
||||
prefix_magic(&sb, prefixlen, element_magic);
|
||||
|
||||
strbuf_addstr(&sb, match);
|
||||
item->original = strbuf_detach(&sb, NULL);
|
||||
} else
|
||||
item->original = elt;
|
||||
item->len = strlen(item->match);
|
||||
item->prefix = prefixlen;
|
||||
|
||||
if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&
|
||||
(item->len >= 1 && item->match[item->len - 1] == '/') &&
|
||||
(i = cache_name_pos(item->match, item->len - 1)) >= 0 &&
|
||||
S_ISGITLINK(active_cache[i]->ce_mode)) {
|
||||
item->len--;
|
||||
match[item->len] = '\0';
|
||||
} else {
|
||||
item->original = xstrdup(elt);
|
||||
}
|
||||
|
||||
if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)
|
||||
strip_submodule_slash_cheap(item);
|
||||
|
||||
if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
int ce_len = ce_namelen(ce);
|
||||
strip_submodule_slash_expensive(item);
|
||||
|
||||
if (!S_ISGITLINK(ce->ce_mode))
|
||||
continue;
|
||||
|
||||
if (item->len <= ce_len || match[ce_len] != '/' ||
|
||||
memcmp(ce->name, match, ce_len))
|
||||
continue;
|
||||
if (item->len == ce_len + 1) {
|
||||
/* strip trailing slash */
|
||||
item->len--;
|
||||
match[item->len] = '\0';
|
||||
} else
|
||||
die (_("Pathspec '%s' is in submodule '%.*s'"),
|
||||
elt, ce_len, ce->name);
|
||||
}
|
||||
|
||||
if (magic & PATHSPEC_LITERAL)
|
||||
if (magic & PATHSPEC_LITERAL) {
|
||||
item->nowildcard_len = item->len;
|
||||
else {
|
||||
} else {
|
||||
item->nowildcard_len = simple_length(item->match);
|
||||
if (item->nowildcard_len < prefixlen)
|
||||
item->nowildcard_len = prefixlen;
|
||||
}
|
||||
|
||||
item->flags = 0;
|
||||
if (magic & PATHSPEC_GLOB) {
|
||||
/*
|
||||
|
@ -315,7 +393,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||
/* sanity checks, pathspec matchers assume these are sane */
|
||||
assert(item->nowildcard_len <= item->len &&
|
||||
item->prefix <= item->len);
|
||||
return magic;
|
||||
}
|
||||
|
||||
static int pathspec_item_cmp(const void *a_, const void *b_)
|
||||
|
@ -328,22 +405,22 @@ static int pathspec_item_cmp(const void *a_, const void *b_)
|
|||
}
|
||||
|
||||
static void NORETURN unsupported_magic(const char *pattern,
|
||||
unsigned magic,
|
||||
unsigned short_magic)
|
||||
unsigned magic)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
int i, n;
|
||||
for (n = i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
|
||||
const struct pathspec_magic *m = pathspec_magic + i;
|
||||
if (!(magic & m->bit))
|
||||
continue;
|
||||
if (sb.len)
|
||||
strbuf_addch(&sb, ' ');
|
||||
if (short_magic & m->bit)
|
||||
strbuf_addf(&sb, "'%c'", m->mnemonic);
|
||||
strbuf_addstr(&sb, ", ");
|
||||
|
||||
if (m->mnemonic)
|
||||
strbuf_addf(&sb, _("'%s' (mnemonic: '%c')"),
|
||||
m->name, m->mnemonic);
|
||||
else
|
||||
strbuf_addf(&sb, "'%s'", m->name);
|
||||
n++;
|
||||
}
|
||||
/*
|
||||
* We may want to substitute "this command" with a command
|
||||
|
@ -381,8 +458,6 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||
|
||||
/* No arguments with prefix -> prefix pathspec */
|
||||
if (!entry) {
|
||||
static const char *raw[2];
|
||||
|
||||
if (flags & PATHSPEC_PREFER_FULL)
|
||||
return;
|
||||
|
||||
|
@ -390,14 +465,11 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||
die("BUG: PATHSPEC_PREFER_CWD requires arguments");
|
||||
|
||||
pathspec->items = item = xcalloc(1, sizeof(*item));
|
||||
item->match = prefix;
|
||||
item->original = prefix;
|
||||
item->match = xstrdup(prefix);
|
||||
item->original = xstrdup(prefix);
|
||||
item->nowildcard_len = item->len = strlen(prefix);
|
||||
item->prefix = item->len;
|
||||
raw[0] = prefix;
|
||||
raw[1] = NULL;
|
||||
pathspec->nr = 1;
|
||||
pathspec->_raw = raw;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -415,25 +487,17 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||
pathspec->nr = n;
|
||||
ALLOC_ARRAY(pathspec->items, n);
|
||||
item = pathspec->items;
|
||||
pathspec->_raw = argv;
|
||||
prefixlen = prefix ? strlen(prefix) : 0;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
unsigned short_magic;
|
||||
entry = argv[i];
|
||||
|
||||
item[i].magic = prefix_pathspec(item + i, &short_magic,
|
||||
argv + i, flags,
|
||||
prefix, prefixlen, entry);
|
||||
if ((flags & PATHSPEC_LITERAL_PATH) &&
|
||||
!(magic_mask & PATHSPEC_LITERAL))
|
||||
item[i].magic |= PATHSPEC_LITERAL;
|
||||
init_pathspec_item(item + i, flags, prefix, prefixlen, entry);
|
||||
|
||||
if (item[i].magic & PATHSPEC_EXCLUDE)
|
||||
nr_exclude++;
|
||||
if (item[i].magic & magic_mask)
|
||||
unsupported_magic(entry,
|
||||
item[i].magic & magic_mask,
|
||||
short_magic);
|
||||
unsupported_magic(entry, item[i].magic & magic_mask);
|
||||
|
||||
if ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&
|
||||
has_symlink_leading_path(item[i].match, item[i].len)) {
|
||||
|
@ -457,45 +521,29 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* N.B. get_pathspec() is deprecated in favor of the "struct pathspec"
|
||||
* based interface - see pathspec.c:parse_pathspec().
|
||||
*
|
||||
* Arguments:
|
||||
* - prefix - a path relative to the root of the working tree
|
||||
* - pathspec - a list of paths underneath the prefix path
|
||||
*
|
||||
* Iterates over pathspec, prepending each path with prefix,
|
||||
* and return the resulting list.
|
||||
*
|
||||
* If pathspec is empty, return a singleton list containing prefix.
|
||||
*
|
||||
* If pathspec and prefix are both empty, return an empty list.
|
||||
*
|
||||
* This is typically used by built-in commands such as add.c, in order
|
||||
* to normalize argv arguments provided to the built-in into a list of
|
||||
* paths to process, all relative to the root of the working tree.
|
||||
*/
|
||||
const char **get_pathspec(const char *prefix, const char **pathspec)
|
||||
{
|
||||
struct pathspec ps;
|
||||
parse_pathspec(&ps,
|
||||
PATHSPEC_ALL_MAGIC &
|
||||
~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
|
||||
PATHSPEC_PREFER_CWD,
|
||||
prefix, pathspec);
|
||||
return ps._raw;
|
||||
}
|
||||
|
||||
void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
|
||||
{
|
||||
int i;
|
||||
|
||||
*dst = *src;
|
||||
ALLOC_ARRAY(dst->items, dst->nr);
|
||||
COPY_ARRAY(dst->items, src->items, dst->nr);
|
||||
|
||||
for (i = 0; i < dst->nr; i++) {
|
||||
dst->items[i].match = xstrdup(src->items[i].match);
|
||||
dst->items[i].original = xstrdup(src->items[i].original);
|
||||
}
|
||||
}
|
||||
|
||||
void clear_pathspec(struct pathspec *pathspec)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pathspec->nr; i++) {
|
||||
free(pathspec->items[i].match);
|
||||
free(pathspec->items[i].original);
|
||||
}
|
||||
free(pathspec->items);
|
||||
pathspec->items = NULL;
|
||||
pathspec->nr = 0;
|
||||
}
|
||||
|
|
|
@ -19,15 +19,14 @@
|
|||
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */
|
||||
|
||||
struct pathspec {
|
||||
const char **_raw; /* get_pathspec() result, not freed by clear_pathspec() */
|
||||
int nr;
|
||||
unsigned int has_wildcard:1;
|
||||
unsigned int recursive:1;
|
||||
unsigned magic;
|
||||
int max_depth;
|
||||
struct pathspec_item {
|
||||
const char *match;
|
||||
const char *original;
|
||||
char *match;
|
||||
char *original;
|
||||
unsigned magic;
|
||||
int len, prefix;
|
||||
int nowildcard_len;
|
||||
|
|
Загрузка…
Ссылка в новой задаче