#include "cache.h"
+#include "attr.h"
+
/*
* convert.c - convert a file when checking it out and checking it in.
*
* 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;
return 0;
}
-int convert_to_git(const char *path, char **bufp, unsigned long *sizep)
+static int crlf_to_git(const char *path, char **bufp, unsigned long *sizep, int action)
{
char *buffer, *nbuf;
unsigned long size, nsize;
struct text_stat stats;
- /*
- * FIXME! Other pluggable conversions should go here,
- * based on filename patterns. Right now we just do the
- * stupid auto-CRLF one.
- */
- if (!auto_crlf)
+ if ((action == CRLF_BINARY) || (action == CRLF_GUESS && !auto_crlf))
return 0;
size = *sizep;
if (!stats.cr)
return 0;
- /*
- * 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;
-
- /*
- * And add some heuristics for binary vs text, of course...
- */
- if (is_binary(size, &stats))
- return 0;
+ 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;
+
+ /*
+ * And add some heuristics for binary vs text, of course...
+ */
+ if (is_binary(size, &stats))
+ return 0;
+ }
/*
* Ok, allocate a new buffer, fill it in, and return true
nbuf = xmalloc(nsize);
*bufp = nbuf;
*sizep = nsize;
- do {
- unsigned char c = *buffer++;
- if (c != '\r')
- *nbuf++ = c;
- } while (--size);
+
+ 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++;
+ if (c != '\r')
+ *nbuf++ = c;
+ } while (--size);
+ } else {
+ do {
+ unsigned char c = *buffer++;
+ if (! (c == '\r' && (1 < size && *buffer == '\n')))
+ *nbuf++ = c;
+ } while (--size);
+ }
return 1;
}
-int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
+static int crlf_to_worktree(const char *path, char **bufp, unsigned long *sizep, int action)
{
char *buffer, *nbuf;
unsigned long size, nsize;
struct text_stat stats;
unsigned char last;
- /*
- * FIXME! Other pluggable conversions should go here,
- * based on filename patterns. Right now we just do the
- * stupid auto-CRLF one.
- */
- if (auto_crlf <= 0)
+ if ((action == CRLF_BINARY) || (action == CRLF_INPUT) ||
+ (action == CRLF_GUESS && auto_crlf <= 0))
return 0;
size = *sizep;
if (stats.lf == stats.crlf)
return 0;
- /* If we have any bare CR characters, we're not going to touch it */
- if (stats.cr != stats.crlf)
- return 0;
+ 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;
- if (is_binary(size, &stats))
- return 0;
+ if (is_binary(size, &stats))
+ return 0;
+ }
/*
* Ok, allocate a new buffer, fill it in, and return true
return 1;
}
+
+static void setup_crlf_check(struct git_attr_check *check)
+{
+ static struct git_attr *attr_crlf;
+
+ if (!attr_crlf)
+ attr_crlf = git_attr("crlf", 4);
+ check->attr = attr_crlf;
+}
+
+static int git_path_check_crlf(const char *path)
+{
+ 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 CRLF_TEXT;
+ else if (ATTR_FALSE(value))
+ return CRLF_BINARY;
+ else if (ATTR_UNSET(value))
+ ;
+ else if (!strcmp(value, "input"))
+ return CRLF_INPUT;
+ /* fallthru */
+ }
+ return CRLF_GUESS;
+}
+
+int convert_to_git(const char *path, char **bufp, unsigned long *sizep)
+{
+ return crlf_to_git(path, bufp, sizep, git_path_check_crlf(path));
+}
+
+int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
+{
+ return crlf_to_worktree(path, bufp, sizep, git_path_check_crlf(path));
+}