Git fork
at reftables-rust 210 lines 6.9 kB view raw
1#ifndef PATHSPEC_H 2#define PATHSPEC_H 3 4struct index_state; 5 6/* Pathspec magic */ 7#define PATHSPEC_FROMTOP (1<<0) 8#define PATHSPEC_MAXDEPTH (1<<1) 9#define PATHSPEC_LITERAL (1<<2) 10#define PATHSPEC_GLOB (1<<3) 11#define PATHSPEC_ICASE (1<<4) 12#define PATHSPEC_EXCLUDE (1<<5) 13#define PATHSPEC_ATTR (1<<6) 14#define PATHSPEC_ALL_MAGIC \ 15 (PATHSPEC_FROMTOP | \ 16 PATHSPEC_MAXDEPTH | \ 17 PATHSPEC_LITERAL | \ 18 PATHSPEC_GLOB | \ 19 PATHSPEC_ICASE | \ 20 PATHSPEC_EXCLUDE | \ 21 PATHSPEC_ATTR) 22 23#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */ 24 25/** 26 * See glossary-content.txt for the syntax of pathspec. 27 * In memory, a pathspec set is represented by "struct pathspec" and is 28 * prepared by parse_pathspec(). 29 */ 30struct pathspec { 31 int nr; 32 unsigned int has_wildcard:1; 33 unsigned int recursive:1; 34 unsigned int recurse_submodules:1; 35 unsigned magic; 36 int max_depth; 37 struct pathspec_item { 38 char *match; 39 char *original; 40 unsigned magic; 41 int len, prefix; 42 int nowildcard_len; 43 int flags; 44 int attr_match_nr; 45 struct attr_match { 46 char *value; 47 enum attr_match_mode { 48 MATCH_SET, 49 MATCH_UNSET, 50 MATCH_VALUE, 51 MATCH_UNSPECIFIED 52 } match_mode; 53 } *attr_match; 54 struct attr_check *attr_check; 55 } *items; 56}; 57 58#define GUARD_PATHSPEC(ps, mask) \ 59 do { \ 60 if ((ps)->magic & ~(mask)) \ 61 BUG("unsupported magic %x", (ps)->magic & ~(mask)); \ 62 } while (0) 63 64/* parse_pathspec flags */ 65#define PATHSPEC_PREFER_CWD (1<<0) /* No args means match cwd */ 66#define PATHSPEC_PREFER_FULL (1<<1) /* No args means match everything */ 67#define PATHSPEC_MAXDEPTH_VALID (1<<2) /* max_depth field is valid */ 68/* die if a symlink is part of the given path's directory */ 69#define PATHSPEC_SYMLINK_LEADING_PATH (1<<3) 70#define PATHSPEC_PREFIX_ORIGIN (1<<4) 71#define PATHSPEC_KEEP_ORDER (1<<5) 72/* 73 * For the callers that just need pure paths from somewhere else, not 74 * from command line. Global --*-pathspecs options are ignored. No 75 * magic is parsed in each pathspec either. If PATHSPEC_LITERAL is 76 * allowed, then it will automatically set for every pathspec. 77 */ 78#define PATHSPEC_LITERAL_PATH (1<<6) 79/* 80 * For git diff --no-index, indicate that we are operating without 81 * a repository or index. 82 */ 83#define PATHSPEC_NO_REPOSITORY (1<<7) 84 85/** 86 * Given command line arguments and a prefix, convert the input to 87 * pathspec. die() if any magic in magic_mask is used. 88 * 89 * Any arguments used are copied. It is safe for the caller to modify 90 * or free 'prefix' and 'args' after calling this function. 91 * 92 * - magic_mask specifies what features that are NOT supported by the following 93 * code. If a user attempts to use such a feature, parse_pathspec() can reject 94 * it early. 95 * 96 * - flags specifies other things that the caller wants parse_pathspec to 97 * perform. 98 * 99 * - prefix and args come from cmd_* functions 100 * 101 * parse_pathspec() helps catch unsupported features and reject them politely. 102 * At a lower level, different pathspec-related functions may not support the 103 * same set of features. Such pathspec-sensitive functions are guarded with 104 * GUARD_PATHSPEC(), which will die in an unfriendly way when an unsupported 105 * feature is requested. 106 * 107 * The command designers are supposed to make sure that GUARD_PATHSPEC() never 108 * dies. They have to make sure all unsupported features are caught by 109 * parse_pathspec(), not by GUARD_PATHSPEC. grepping GUARD_PATHSPEC() should 110 * give the designers all pathspec-sensitive codepaths and what features they 111 * support. 112 * 113 * A similar process is applied when a new pathspec magic is added. The designer 114 * lifts the GUARD_PATHSPEC restriction in the functions that support the new 115 * magic while at the same time making sure this new feature will be 116 * caught at parse_pathspec() in commands that cannot handle the new magic in 117 * some cases. grepping parse_pathspec() should help. 118 */ 119void parse_pathspec(struct pathspec *pathspec, 120 unsigned magic_mask, 121 unsigned flags, 122 const char *prefix, 123 const char **args); 124/* 125 * Same as parse_pathspec() but uses file as input. 126 * When 'file' is exactly "-" it uses 'stdin' instead. 127 */ 128void parse_pathspec_file(struct pathspec *pathspec, 129 unsigned magic_mask, 130 unsigned flags, 131 const char *prefix, 132 const char *file, 133 int nul_term_line); 134 135void copy_pathspec(struct pathspec *dst, const struct pathspec *src); 136void clear_pathspec(struct pathspec *); 137 138/* 139 * Add a human-readable string to "out" representing the PATHSPEC_* flags set 140 * in "magic". The result is suitable for error messages, but not for 141 * parsing as pathspec magic itself (you get 'icase' with quotes, not 142 * :(icase)). 143 */ 144void pathspec_magic_names(unsigned magic, struct strbuf *out); 145 146static inline int ps_strncmp(const struct pathspec_item *item, 147 const char *s1, const char *s2, size_t n) 148{ 149 if (item->magic & PATHSPEC_ICASE) 150 return strncasecmp(s1, s2, n); 151 else 152 return strncmp(s1, s2, n); 153} 154 155static inline int ps_strcmp(const struct pathspec_item *item, 156 const char *s1, const char *s2) 157{ 158 if (item->magic & PATHSPEC_ICASE) 159 return strcasecmp(s1, s2); 160 else 161 return strcmp(s1, s2); 162} 163 164enum ps_skip_worktree_action { 165 PS_HEED_SKIP_WORKTREE = 0, 166 PS_IGNORE_SKIP_WORKTREE = 1 167}; 168void add_pathspec_matches_against_index(const struct pathspec *pathspec, 169 struct index_state *istate, 170 char *seen, 171 enum ps_skip_worktree_action sw_action); 172char *find_pathspecs_matching_against_index(const struct pathspec *pathspec, 173 struct index_state *istate, 174 enum ps_skip_worktree_action sw_action); 175char *find_pathspecs_matching_skip_worktree(const struct pathspec *pathspec); 176static inline int matches_skip_worktree(const struct pathspec *pathspec, 177 int item, char **seen_ptr) 178{ 179 if (!*seen_ptr) 180 *seen_ptr = find_pathspecs_matching_skip_worktree(pathspec); 181 return (*seen_ptr)[item]; 182} 183int match_pathspec_attrs(struct index_state *istate, 184 const char *name, int namelen, 185 const struct pathspec_item *item); 186 187int match_pathspec(struct index_state *istate, 188 const struct pathspec *pathspec, 189 const char *name, int namelen, 190 int prefix, char *seen, int is_dir); 191 192/* Set both DO_MATCH_DIRECTORY and DO_MATCH_LEADING_PATHSPEC if is_dir true */ 193int match_leading_pathspec(struct index_state *istate, 194 const struct pathspec *ps, 195 const char *name, int namelen, 196 int prefix, char *seen, int is_dir); 197 198/* 199 * Determine whether a pathspec will match only entire index entries (non-sparse 200 * files and/or entire sparse directories). If the pathspec has the potential to 201 * match partial contents of a sparse directory, return 1 to indicate the index 202 * should be expanded to match the appropriate index entries. 203 * 204 * For the sake of simplicity, always return 1 if using a more complex "magic" 205 * pathspec. 206 */ 207int pathspec_needs_expanded_index(struct index_state *istate, 208 const struct pathspec *pathspec); 209 210#endif /* PATHSPEC_H */