diff options
author | Junio C Hamano <gitster@pobox.com> | 2010-06-21 06:02:49 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2010-06-21 06:02:49 -0700 |
commit | d5cff17edaf438bbf45a2130e9cadc0c938291d6 (patch) | |
tree | 19acab3f0fbb8fa480cb45a315d0dac2e6f16ab1 /convert.c | |
parent | d249515f297d47df6d79167b988eaa7db0981178 (diff) | |
parent | 942e7747678ecf5f118ea5b2d0c763166de21f3a (diff) | |
download | git-d5cff17edaf438bbf45a2130e9cadc0c938291d6.tar.gz |
Merge branch 'eb/core-eol'
* eb/core-eol:
Add "core.eol" config variable
Rename the "crlf" attribute "text"
Add per-repository eol normalization
Add tests for per-repository eol normalization
Conflicts:
Documentation/config.txt
Makefile
Diffstat (limited to 'convert.c')
-rw-r--r-- | convert.c | 150 |
1 files changed, 110 insertions, 40 deletions
@@ -8,13 +8,17 @@ * This should use the pathname to decide on whether it wants to do some * more interesting conversions (automatic gzip/unzip, general format * conversions etc etc), but by default it just does automatic CRLF<->LF - * translation when the "auto_crlf" option is set. + * translation when the "text" attribute or "auto_crlf" option is set. */ -#define CRLF_GUESS (-1) -#define CRLF_BINARY 0 -#define CRLF_TEXT 1 -#define CRLF_INPUT 2 +enum action { + CRLF_GUESS = -1, + CRLF_BINARY = 0, + CRLF_TEXT, + CRLF_INPUT, + CRLF_CRLF, + CRLF_AUTO, +}; struct text_stat { /* NUL, CR, LF and CRLF counts */ @@ -89,31 +93,55 @@ static int is_binary(unsigned long size, struct text_stat *stats) return 0; } -static void check_safe_crlf(const char *path, int action, +static enum eol determine_output_conversion(enum action action) { + switch (action) { + case CRLF_BINARY: + return EOL_UNSET; + case CRLF_CRLF: + return EOL_CRLF; + case CRLF_INPUT: + return EOL_LF; + case CRLF_GUESS: + if (!auto_crlf) + return EOL_UNSET; + /* fall through */ + case CRLF_TEXT: + case CRLF_AUTO: + if (auto_crlf == AUTO_CRLF_TRUE) + return EOL_CRLF; + else if (auto_crlf == AUTO_CRLF_INPUT) + return EOL_LF; + else if (eol == EOL_UNSET) + return EOL_NATIVE; + } + return eol; +} + +static void check_safe_crlf(const char *path, enum action action, struct text_stat *stats, enum safe_crlf checksafe) { if (!checksafe) return; - if (action == CRLF_INPUT || auto_crlf <= 0) { + if (determine_output_conversion(action) == EOL_LF) { /* * CRLFs would not be restored by checkout: * check if we'd remove CRLFs */ if (stats->crlf) { if (checksafe == SAFE_CRLF_WARN) - warning("CRLF will be replaced by LF in %s.", path); + warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.", path); else /* i.e. SAFE_CRLF_FAIL */ die("CRLF would be replaced by LF in %s.", path); } - } else if (auto_crlf > 0) { + } else if (determine_output_conversion(action) == EOL_CRLF) { /* * CRLFs would be added by checkout: * check if we have "naked" LFs */ if (stats->lf != stats->crlf) { if (checksafe == SAFE_CRLF_WARN) - warning("LF will be replaced by CRLF in %s", path); + warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.", path); else /* i.e. SAFE_CRLF_FAIL */ die("LF would be replaced by CRLF in %s", path); } @@ -158,17 +186,18 @@ static int has_cr_in_index(const char *path) } static int crlf_to_git(const char *path, const char *src, size_t len, - struct strbuf *buf, int action, enum safe_crlf checksafe) + struct strbuf *buf, enum action action, enum safe_crlf checksafe) { struct text_stat stats; char *dst; - if ((action == CRLF_BINARY) || !auto_crlf || !len) + if (action == CRLF_BINARY || + (action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) || !len) return 0; gather_stats(src, len, &stats); - if (action == CRLF_GUESS) { + if (action == CRLF_AUTO || action == CRLF_GUESS) { /* * We're currently not going to even try to convert stuff * that has bare CR characters. Does anybody do that crazy @@ -183,12 +212,14 @@ static int crlf_to_git(const char *path, const char *src, size_t len, if (is_binary(len, &stats)) return 0; - /* - * If the file in the index has any CR in it, do not convert. - * This is the new safer autocrlf handling. - */ - if (has_cr_in_index(path)) - return 0; + if (action == CRLF_GUESS) { + /* + * If the file in the index has any CR in it, do not convert. + * This is the new safer autocrlf handling. + */ + if (has_cr_in_index(path)) + return 0; + } } check_safe_crlf(path, action, &stats, checksafe); @@ -201,7 +232,7 @@ static int crlf_to_git(const char *path, const char *src, size_t len, if (strbuf_avail(buf) + buf->len < len) strbuf_grow(buf, len - buf->len); dst = buf->buf; - if (action == CRLF_GUESS) { + if (action == CRLF_AUTO || 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 @@ -224,16 +255,12 @@ static int crlf_to_git(const char *path, const char *src, size_t len, } static int crlf_to_worktree(const char *path, const char *src, size_t len, - struct strbuf *buf, int action) + struct strbuf *buf, enum action action) { char *to_free = NULL; struct text_stat stats; - if ((action == CRLF_BINARY) || (action == CRLF_INPUT) || - auto_crlf <= 0) - return 0; - - if (!len) + if (!len || determine_output_conversion(action) != EOL_CRLF) return 0; gather_stats(src, len, &stats); @@ -246,11 +273,13 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len, if (stats.lf == stats.crlf) return 0; - if (action == CRLF_GUESS) { - /* If we have any CR or CRLF line endings, we do not touch it */ - /* This is the new safer autocrlf-handling */ - if (stats.cr > 0 || stats.crlf > 0) - return 0; + if (action == CRLF_AUTO || action == CRLF_GUESS) { + if (action == CRLF_GUESS) { + /* If we have any CR or CRLF line endings, we do not touch it */ + /* This is the new safer autocrlf-handling */ + if (stats.cr > 0 || stats.crlf > 0) + return 0; + } /* If we have any bare CR characters, we're not going to touch it */ if (stats.cr != stats.crlf) @@ -425,12 +454,16 @@ static int read_convert_config(const char *var, const char *value, void *cb) static void setup_convert_check(struct git_attr_check *check) { + static struct git_attr *attr_text; static struct git_attr *attr_crlf; + static struct git_attr *attr_eol; static struct git_attr *attr_ident; static struct git_attr *attr_filter; - if (!attr_crlf) { + if (!attr_text) { + attr_text = git_attr("text"); attr_crlf = git_attr("crlf"); + attr_eol = git_attr("eol"); attr_ident = git_attr("ident"); attr_filter = git_attr("filter"); user_convert_tail = &user_convert; @@ -439,6 +472,8 @@ static void setup_convert_check(struct git_attr_check *check) check[0].attr = attr_crlf; check[1].attr = attr_ident; check[2].attr = attr_filter; + check[3].attr = attr_eol; + check[4].attr = attr_text; } static int count_ident(const char *cp, unsigned long size) @@ -619,9 +654,24 @@ static int git_path_check_crlf(const char *path, struct git_attr_check *check) ; else if (!strcmp(value, "input")) return CRLF_INPUT; + else if (!strcmp(value, "auto")) + return CRLF_AUTO; return CRLF_GUESS; } +static int git_path_check_eol(const char *path, struct git_attr_check *check) +{ + const char *value = check->value; + + if (ATTR_UNSET(value)) + ; + else if (!strcmp(value, "lf")) + return EOL_LF; + else if (!strcmp(value, "crlf")) + return EOL_CRLF; + return EOL_UNSET; +} + static struct convert_driver *git_path_check_convert(const char *path, struct git_attr_check *check) { @@ -643,20 +693,34 @@ 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) { + if (text_attr == CRLF_BINARY) + return CRLF_BINARY; + if (eol_attr == EOL_LF) + return CRLF_INPUT; + if (eol_attr == EOL_CRLF) + return CRLF_CRLF; + return text_attr; +} + int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst, enum safe_crlf checksafe) { - struct git_attr_check check[3]; - int crlf = CRLF_GUESS; + struct git_attr_check check[5]; + enum action action = CRLF_GUESS; + enum eol eol_attr = EOL_UNSET; int ident = 0, ret = 0; const char *filter = NULL; setup_convert_check(check); if (!git_checkattr(path, ARRAY_SIZE(check), check)) { struct convert_driver *drv; - crlf = git_path_check_crlf(path, check + 0); + action = git_path_check_crlf(path, check + 4); + if (action == CRLF_GUESS) + action = git_path_check_crlf(path, check + 0); ident = git_path_check_ident(path, check + 1); drv = git_path_check_convert(path, check + 2); + eol_attr = git_path_check_eol(path, check + 3); if (drv && drv->clean) filter = drv->clean; } @@ -666,7 +730,8 @@ int convert_to_git(const char *path, const char *src, size_t len, src = dst->buf; len = dst->len; } - ret |= crlf_to_git(path, src, len, dst, crlf, checksafe); + action = determine_action(action, eol_attr); + ret |= crlf_to_git(path, src, len, dst, action, checksafe); if (ret) { src = dst->buf; len = dst->len; @@ -676,17 +741,21 @@ int convert_to_git(const char *path, const char *src, size_t len, int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst) { - struct git_attr_check check[3]; - int crlf = CRLF_GUESS; + struct git_attr_check check[5]; + enum action action = CRLF_GUESS; + enum eol eol_attr = EOL_UNSET; int ident = 0, ret = 0; const char *filter = NULL; setup_convert_check(check); if (!git_checkattr(path, ARRAY_SIZE(check), check)) { struct convert_driver *drv; - crlf = git_path_check_crlf(path, check + 0); + action = git_path_check_crlf(path, check + 4); + if (action == CRLF_GUESS) + action = git_path_check_crlf(path, check + 0); ident = git_path_check_ident(path, check + 1); drv = git_path_check_convert(path, check + 2); + eol_attr = git_path_check_eol(path, check + 3); if (drv && drv->smudge) filter = drv->smudge; } @@ -696,7 +765,8 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc src = dst->buf; len = dst->len; } - ret |= crlf_to_worktree(path, src, len, dst, crlf); + action = determine_action(action, eol_attr); + ret |= crlf_to_worktree(path, src, len, dst, action); if (ret) { src = dst->buf; len = dst->len; |