]> asedeno.scripts.mit.edu Git - git.git/blobdiff - convert.c
Merge branch 'maint'
[git.git] / convert.c
index a5f60c7c6b729efbc7b98b1f5ac098cbf1bf9728..ad106ef35fb0729709b243d6292980f15cd1b0a5 100644 (file)
--- a/convert.c
+++ b/convert.c
  * translation when the "auto_crlf" option is set.
  */
 
+#define CRLF_GUESS     (-1)
+#define CRLF_BINARY    0
+#define CRLF_TEXT      1
+#define CRLF_INPUT     2
+
 struct text_stat {
        /* CR, LF and CRLF counts */
        unsigned cr, lf, crlf;
@@ -74,143 +79,128 @@ static int is_binary(unsigned long size, struct text_stat *stats)
        return 0;
 }
 
-static int crlf_to_git(const char *path, char **bufp, unsigned long *sizep, int guess)
+static char *crlf_to_git(const char *path, const char *src, unsigned long *sizep, int action)
 {
-       char *buffer, *nbuf;
+       char *buffer, *dst;
        unsigned long size, nsize;
        struct text_stat stats;
 
-       if (guess && !auto_crlf)
-               return 0;
+       if ((action == CRLF_BINARY) || (action == CRLF_GUESS && !auto_crlf))
+               return NULL;
 
        size = *sizep;
        if (!size)
-               return 0;
-       buffer = *bufp;
+               return NULL;
 
-       gather_stats(buffer, size, &stats);
+       gather_stats(src, size, &stats);
 
        /* No CR? Nothing to convert, regardless. */
        if (!stats.cr)
-               return 0;
+               return NULL;
 
-       if (guess) {
+       if (action == CRLF_GUESS) {
                /*
                 * We're currently not going to even try to convert stuff
                 * that has bare CR characters. Does anybody do that crazy
                 * stuff?
                 */
                if (stats.cr != stats.crlf)
-                       return 0;
+                       return NULL;
 
                /*
                 * And add some heuristics for binary vs text, of course...
                 */
                if (is_binary(size, &stats))
-                       return 0;
+                       return NULL;
        }
 
        /*
-        * Ok, allocate a new buffer, fill it in, and return true
-        * to let the caller know that we switched buffers on it.
+        * Ok, allocate a new buffer, fill it in, and return it
+        * to let the caller know that we switched buffers.
         */
        nsize = size - stats.crlf;
-       nbuf = xmalloc(nsize);
-       *bufp = nbuf;
+       buffer = xmalloc(nsize);
        *sizep = nsize;
 
-       if (guess) {
+       dst = buffer;
+       if (action == CRLF_GUESS) {
+               /*
+                * If we guessed, we already know we rejected a file with
+                * lone CR, and we can strip a CR without looking at what
+                * follow it.
+                */
                do {
-                       unsigned char c = *buffer++;
+                       unsigned char c = *src++;
                        if (c != '\r')
-                               *nbuf++ = c;
+                               *dst++ = c;
                } while (--size);
        } else {
                do {
-                       unsigned char c = *buffer++;
-                       if (! (c == '\r' && (1 < size && *buffer == '\n')))
-                               *nbuf++ = c;
+                       unsigned char c = *src++;
+                       if (! (c == '\r' && (1 < size && *src == '\n')))
+                               *dst++ = c;
                } while (--size);
        }
 
-       return 1;
-}
-
-static int autocrlf_to_git(const char *path, char **bufp, unsigned long *sizep)
-{
-       return crlf_to_git(path, bufp, sizep, 1);
+       return buffer;
 }
 
-static int forcecrlf_to_git(const char *path, char **bufp, unsigned long *sizep)
+static char *crlf_to_worktree(const char *path, const char *src, unsigned long *sizep, int action)
 {
-       return crlf_to_git(path, bufp, sizep, 0);
-}
-
-static int crlf_to_working_tree(const char *path, char **bufp, unsigned long *sizep, int guess)
-{
-       char *buffer, *nbuf;
+       char *buffer, *dst;
        unsigned long size, nsize;
        struct text_stat stats;
        unsigned char last;
 
-       if (guess && auto_crlf <= 0)
-               return 0;
+       if ((action == CRLF_BINARY) || (action == CRLF_INPUT) ||
+           (action == CRLF_GUESS && auto_crlf <= 0))
+               return NULL;
 
        size = *sizep;
        if (!size)
-               return 0;
-       buffer = *bufp;
+               return NULL;
 
-       gather_stats(buffer, size, &stats);
+       gather_stats(src, size, &stats);
 
        /* No LF? Nothing to convert, regardless. */
        if (!stats.lf)
-               return 0;
+               return NULL;
 
        /* Was it already in CRLF format? */
        if (stats.lf == stats.crlf)
-               return 0;
+               return NULL;
 
-       if (guess) {
+       if (action == CRLF_GUESS) {
                /* If we have any bare CR characters, we're not going to touch it */
                if (stats.cr != stats.crlf)
-                       return 0;
+                       return NULL;
 
                if (is_binary(size, &stats))
-                       return 0;
+                       return NULL;
        }
 
        /*
-        * Ok, allocate a new buffer, fill it in, and return true
-        * to let the caller know that we switched buffers on it.
+        * Ok, allocate a new buffer, fill it in, and return it
+        * to let the caller know that we switched buffers.
         */
        nsize = size + stats.lf - stats.crlf;
-       nbuf = xmalloc(nsize);
-       *bufp = nbuf;
+       buffer = xmalloc(nsize);
        *sizep = nsize;
        last = 0;
+
+       dst = buffer;
        do {
-               unsigned char c = *buffer++;
+               unsigned char c = *src++;
                if (c == '\n' && last != '\r')
-                       *nbuf++ = '\r';
-               *nbuf++ = c;
+                       *dst++ = '\r';
+               *dst++ = c;
                last = c;
        } while (--size);
 
-       return 1;
+       return buffer;
 }
 
-static int autocrlf_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
-{
-       return crlf_to_working_tree(path, bufp, sizep, 1);
-}
-
-static int forcecrlf_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
-{
-       return crlf_to_working_tree(path, bufp, sizep, 0);
-}
-
-static void setup_crlf_check(struct git_attr_check *check)
+static void setup_convert_check(struct git_attr_check *check)
 {
        static struct git_attr *attr_crlf;
 
@@ -219,47 +209,41 @@ static void setup_crlf_check(struct git_attr_check *check)
        check->attr = attr_crlf;
 }
 
-static int git_path_check_crlf(const char *path)
+static int git_path_check_crlf(const char *path, struct git_attr_check *check)
 {
-       struct git_attr_check attr_crlf_check;
-
-       setup_crlf_check(&attr_crlf_check);
-
-       if (!git_checkattr(path, 1, &attr_crlf_check)) {
-               const char *value = attr_crlf_check.value;
-               if (ATTR_TRUE(value))
-                       return 1;
-               else if (ATTR_FALSE(value))
-                       return 0;
-               else if (ATTR_UNSET(value))
-                       ;
-               else
-                       die("unknown value %s given to 'crlf' attribute",
-                           (char *)value);
-       }
-       return -1;
+       const char *value = check->value;
+
+       if (ATTR_TRUE(value))
+               return CRLF_TEXT;
+       else if (ATTR_FALSE(value))
+               return CRLF_BINARY;
+       else if (ATTR_UNSET(value))
+               ;
+       else if (!strcmp(value, "input"))
+               return CRLF_INPUT;
+       return CRLF_GUESS;
 }
 
-int convert_to_git(const char *path, char **bufp, unsigned long *sizep)
+char *convert_to_git(const char *path, const char *src, unsigned long *sizep)
 {
-       switch (git_path_check_crlf(path)) {
-       case 0:
-               return 0;
-       case 1:
-               return forcecrlf_to_git(path, bufp, sizep);
-       default:
-               return autocrlf_to_git(path, bufp, sizep);
+       struct git_attr_check check[1];
+       int crlf = CRLF_GUESS;
+
+       setup_convert_check(check);
+       if (!git_checkattr(path, 1, check)) {
+               crlf = git_path_check_crlf(path, check);
        }
+       return crlf_to_git(path, src, sizep, crlf);
 }
 
-int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
+char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep)
 {
-       switch (git_path_check_crlf(path)) {
-       case 0:
-               return 0;
-       case 1:
-               return forcecrlf_to_working_tree(path, bufp, sizep);
-       default:
-               return autocrlf_to_working_tree(path, bufp, sizep);
+       struct git_attr_check check[1];
+       int crlf = CRLF_GUESS;
+
+       setup_convert_check(check);
+       if (!git_checkattr(path, 1, check)) {
+               crlf = git_path_check_crlf(path, check);
        }
+       return crlf_to_worktree(path, src, sizep, crlf);
 }