attrs->key = git_pool_malloc(attrs->pool, (uint32_t)len + 3);
GITERR_CHECK_ALLOC(attrs->key);
- attrs->key[0] = '0' + from;
+ attrs->key[0] = '0' + (char)from;
attrs->key[1] = '#';
memcpy(&attrs->key[2], path, len);
attrs->key[len + 2] = '\0';
git_repository *repo, void *parsedata, const char *buffer, git_attr_file *attrs)
{
int error = 0;
- const char *scan = NULL;
- char *context = NULL;
+ const char *scan = NULL, *context = NULL;
git_attr_rule *rule = NULL;
GIT_UNUSED(parsedata);
scan = buffer;
/* if subdir file path, convert context for file paths */
- if (attrs->key && git__suffixcmp(attrs->key, "/" GIT_ATTR_FILE) == 0) {
+ if (attrs->key &&
+ git_path_root(attrs->key + 2) < 0 &&
+ git__suffixcmp(attrs->key, "/" GIT_ATTR_FILE) == 0)
context = attrs->key + 2;
- context[strlen(context) - strlen(GIT_ATTR_FILE)] = '\0';
- }
while (!error && *scan) {
/* allocate rule if needed */
- if (!rule && !(rule = git__calloc(1, sizeof(git_attr_rule)))) {
- error = -1;
- break;
+ if (!rule) {
+ if (!(rule = git__calloc(1, sizeof(git_attr_rule)))) {
+ error = -1;
+ break;
+ }
+ rule->match.flags = GIT_ATTR_FNMATCH_ALLOWNEG |
+ GIT_ATTR_FNMATCH_ALLOWMACRO;
}
/* parse the next "pattern attr attr attr" line */
- if (!(error = git_attr_fnmatch__parse_gitattr_format(
+ if (!(error = git_attr_fnmatch__parse(
&rule->match, attrs->pool, context, &scan)) &&
!(error = git_attr_assignment__parse(
repo, attrs->pool, &rule->assigns, &scan)))
git_attr_rule__free(rule);
- /* restore file path used for context */
- if (context)
- context[strlen(context)] = '.'; /* first char of GIT_ATTR_FILE */
-
return error;
}
* GIT_ENOTFOUND if the fnmatch does not require matching, or
* another error code there was an actual problem.
*/
-int git_attr_fnmatch__parse_gitattr_format(
+int git_attr_fnmatch__parse(
git_attr_fnmatch *spec,
git_pool *pool,
const char *source,
const char **base)
{
- const char *pattern;
+ const char *pattern, *scan;
+ int slash_count, allow_space;
assert(spec && base && *base);
+ if (parse_optimized_patterns(spec, pool, *base))
+ return 0;
+
+ spec->flags = (spec->flags & GIT_ATTR_FNMATCH__INCOMING);
+ allow_space = ((spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE) != 0);
+
pattern = *base;
while (git__isspace(*pattern)) pattern++;
return GIT_ENOTFOUND;
}
- if (*pattern == '[') {
+ if (*pattern == '[' && (spec->flags & GIT_ATTR_FNMATCH_ALLOWMACRO) != 0) {
if (strncmp(pattern, "[attr]", 6) == 0) {
spec->flags = spec->flags | GIT_ATTR_FNMATCH_MACRO;
pattern += 6;
/* else a character range like [a-e]* which is accepted */
}
- if (*pattern == '!') {
+ if (*pattern == '!' && (spec->flags & GIT_ATTR_FNMATCH_ALLOWNEG) != 0) {
spec->flags = spec->flags | GIT_ATTR_FNMATCH_NEGATIVE;
pattern++;
}
- if (git_attr_fnmatch__parse_shellglob_format(spec, pool,
- source, &pattern) < 0)
- return -1;
-
- *base = pattern;
-
- return 0;
-}
-
-/*
- * Fills a spec for the purpose of pure pathspec matching, not
- * related to a gitattribute file parsing.
- *
- * This will return 0 if the spec was filled out, or
- * another error code there was an actual problem.
- */
-int git_attr_fnmatch__parse_shellglob_format(
- git_attr_fnmatch *spec,
- git_pool *pool,
- const char *source,
- const char **base)
-{
- const char *pattern, *scan;
- int slash_count, allow_space;
-
- assert(spec && base && *base);
-
- if (parse_optimized_patterns(spec, pool, *base))
- return 0;
-
- allow_space = (spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE) != 0;
- pattern = *base;
-
slash_count = 0;
for (scan = pattern; *scan != '\0'; ++scan) {
/* scan until (non-escaped) white space */
if ((spec->flags & GIT_ATTR_FNMATCH_FULLPATH) != 0 &&
source != NULL && git_path_root(pattern) < 0)
{
- size_t sourcelen = strlen(source);
+ /* use context path minus the trailing filename */
+ char *slash = strrchr(source, '/');
+ size_t sourcelen = slash ? slash - source + 1 : 0;
+
/* given an unrooted fullpath match from a file inside a repo,
* prefix the pattern with the relative directory of the source file
*/
/* match.pattern is stored in a git_pool, so no need to free */
rule->match.pattern = NULL;
rule->match.length = 0;
- rule->match.flags = 0;
}
void git_attr_rule__free(git_attr_rule *rule)