]> git.proxmox.com Git - libgit2.git/blobdiff - src/attr_file.c
Fix core.excludesfile named .gitignore
[libgit2.git] / src / attr_file.c
index ca5f2137c863c60c0cf8e7606d32047f31f830c3..ea92336f7559e22f1bfbcdcd2e2d9c70fc2c8ff6 100644 (file)
@@ -39,7 +39,7 @@ int git_attr_file__new(
                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';
@@ -61,8 +61,7 @@ int git_attr_file__parse_buffer(
        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);
@@ -72,20 +71,24 @@ int git_attr_file__parse_buffer(
        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)))
@@ -111,10 +114,6 @@ int git_attr_file__parse_buffer(
 
        git_attr_rule__free(rule);
 
-       /* restore file path used for context */
-       if (context)
-               context[strlen(context)] = '.'; /* first char of GIT_ATTR_FILE */
-
        return error;
 }
 
@@ -337,16 +336,23 @@ void git_attr_path__free(git_attr_path *info)
  * 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++;
@@ -355,7 +361,7 @@ int git_attr_fnmatch__parse_gitattr_format(
                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;
@@ -363,44 +369,11 @@ int git_attr_fnmatch__parse_gitattr_format(
                /* 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 */
@@ -436,7 +409,10 @@ int git_attr_fnmatch__parse_shellglob_format(
        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
                 */
@@ -636,7 +612,6 @@ static void git_attr_rule__clear(git_attr_rule *rule)
        /* 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)