Code

add support for the SUA layer (interix; windows)
[git.git] / convert.c
index 061fb23d6a196ce96d1d5b3e514d173a58ffe425..01de9a84c21b31a0120065a32a386f27321cdf7b 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -93,7 +93,8 @@ static int is_binary(unsigned long size, struct text_stat *stats)
        return 0;
 }
 
-static enum eol determine_output_conversion(enum action action) {
+static enum eol determine_output_conversion(enum action action)
+{
        switch (action) {
        case CRLF_BINARY:
                return EOL_UNSET;
@@ -319,7 +320,7 @@ struct filter_params {
        const char *cmd;
 };
 
-static int filter_buffer(int fd, void *data)
+static int filter_buffer(int in, int out, void *data)
 {
        /*
         * Spawn cmd and feed the buffer contents through its stdin.
@@ -327,13 +328,15 @@ static int filter_buffer(int fd, void *data)
        struct child_process child_process;
        struct filter_params *params = (struct filter_params *)data;
        int write_err, status;
-       const char *argv[] = { params->cmd, NULL };
+       const char *argv[] = { NULL, NULL };
+
+       argv[0] = params->cmd;
 
        memset(&child_process, 0, sizeof(child_process));
        child_process.argv = argv;
        child_process.use_shell = 1;
        child_process.in = -1;
-       child_process.out = fd;
+       child_process.out = out;
 
        if (start_command(&child_process))
                return error("cannot fork to run external filter %s", params->cmd);
@@ -370,6 +373,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
        memset(&async, 0, sizeof(async));
        async.proc = filter_buffer;
        async.data = &params;
+       async.out = -1;
        params.src = src;
        params.size = len;
        params.cmd = cmd;
@@ -508,6 +512,8 @@ static int count_ident(const char *cp, unsigned long size)
                                cnt++;
                                break;
                        }
+                       if (ch == '\n')
+                               break;
                }
        }
        return cnt;
@@ -538,6 +544,11 @@ static int ident_to_git(const char *path, const char *src, size_t len,
                        dollar = memchr(src + 3, '$', len - 3);
                        if (!dollar)
                                break;
+                       if (memchr(src + 3, '\n', dollar - src - 3)) {
+                               /* Line break before the next dollar. */
+                               continue;
+                       }
+
                        memcpy(dst, "Id$", 3);
                        dst += 3;
                        len -= dollar + 1 - src;
@@ -553,7 +564,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
                              struct strbuf *buf, int ident)
 {
        unsigned char sha1[20];
-       char *to_free = NULL, *dollar;
+       char *to_free = NULL, *dollar, *spc;
        int cnt;
 
        if (!ident)
@@ -589,7 +600,10 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
                } else if (src[2] == ':') {
                        /*
                         * It's possible that an expanded Id has crept its way into the
-                        * repository, we cope with that by stripping the expansion out
+                        * repository, we cope with that by stripping the expansion out.
+                        * This is probably not a good idea, since it will cause changes
+                        * on checkout, which won't go away by stash, but let's keep it
+                        * for git-style ids.
                         */
                        dollar = memchr(src + 3, '$', len - 3);
                        if (!dollar) {
@@ -597,6 +611,20 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
                                break;
                        }
 
+                       if (memchr(src + 3, '\n', dollar - src - 3)) {
+                               /* Line break before the next dollar. */
+                               continue;
+                       }
+
+                       spc = memchr(src + 4, ' ', dollar - src - 4);
+                       if (spc && spc < dollar-1) {
+                               /* There are spaces in unexpected places.
+                                * This is probably an id from some other
+                                * versioning system. Keep it for now.
+                                */
+                               continue;
+                       }
+
                        len -= dollar + 1 - src;
                        src  = dollar + 1;
                } else {
@@ -666,7 +694,8 @@ static int git_path_check_ident(const char *path, struct git_attr_check *check)
        return !!ATTR_TRUE(value);
 }
 
-enum action determine_action(enum action text_attr, enum eol eol_attr) {
+static enum action determine_action(enum action text_attr, enum eol eol_attr)
+{
        if (text_attr == CRLF_BINARY)
                return CRLF_BINARY;
        if (eol_attr == EOL_LF)
@@ -712,7 +741,9 @@ int convert_to_git(const char *path, const char *src, size_t len,
        return ret | ident_to_git(path, src, len, dst, ident);
 }
 
-int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
+static int convert_to_working_tree_internal(const char *path, const char *src,
+                                           size_t len, struct strbuf *dst,
+                                           int normalizing)
 {
        struct git_attr_check check[5];
        enum action action = CRLF_GUESS;
@@ -738,11 +769,32 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc
                src = dst->buf;
                len = dst->len;
        }
-       action = determine_action(action, eol_attr);
-       ret |= crlf_to_worktree(path, src, len, dst, action);
+       /*
+        * CRLF conversion can be skipped if normalizing, unless there
+        * is a smudge filter.  The filter might expect CRLFs.
+        */
+       if (filter || !normalizing) {
+               action = determine_action(action, eol_attr);
+               ret |= crlf_to_worktree(path, src, len, dst, action);
+               if (ret) {
+                       src = dst->buf;
+                       len = dst->len;
+               }
+       }
+       return ret | apply_filter(path, src, len, dst, filter);
+}
+
+int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
+{
+       return convert_to_working_tree_internal(path, src, len, dst, 0);
+}
+
+int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst)
+{
+       int ret = convert_to_working_tree_internal(path, src, len, dst, 1);
        if (ret) {
                src = dst->buf;
                len = dst->len;
        }
-       return ret | apply_filter(path, src, len, dst, filter);
+       return ret | convert_to_git(path, src, len, dst, 0);
 }