#include "cache.h"
+#include "attr.h"
+
/*
* convert.c - convert a file when checking it out and checking it in.
*
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 guess)
{
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 (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;
+ if (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;
+ /*
+ * 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 (guess) {
+ 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 autocrlf_to_git(const char *path, char **bufp, unsigned long *sizep)
+{
+ return crlf_to_git(path, bufp, sizep, 1);
+}
+
+static int forcecrlf_to_git(const char *path, char **bufp, unsigned long *sizep)
+{
+ 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;
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 (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 (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 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 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)) {
+ void *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;
+}
+
+int convert_to_git(const char *path, char **bufp, 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);
+ }
+}
+
+int convert_to_working_tree(const char *path, char **bufp, 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);
+ }
+}