X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=convert.c;h=4534e2c2b003998a590637fc43c0549ff23f71b2;hb=a12c6b0149e3dadd0701dac4fd0ba2463d251650;hp=3bb5a4dd57c669bc59be0e2317ef33b64b024992;hpb=c07aa5b218b9f519c29b5be71fe43cd79365dd37;p=git.git diff --git a/convert.c b/convert.c index 3bb5a4dd5..4534e2c2b 100644 --- a/convert.c +++ b/convert.c @@ -2,6 +2,7 @@ #include "attr.h" #include "run-command.h" #include "quote.h" +#include "sigchain.h" /* * convert.c - convert a file when checking it out and checking it in. @@ -195,9 +196,17 @@ static int crlf_to_git(const char *path, const char *src, size_t len, char *dst; if (crlf_action == CRLF_BINARY || - (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) || !len) + (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) || + (src && !len)) return 0; + /* + * If we are doing a dry-run and have no source buffer, there is + * nothing to analyze; we must assume we would convert. + */ + if (!buf && !src) + return 1; + gather_stats(src, len, &stats); if (crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS) { @@ -231,6 +240,13 @@ static int crlf_to_git(const char *path, const char *src, size_t len, if (!stats.cr) return 0; + /* + * At this point all of our source analysis is done, and we are sure we + * would convert. If we are in dry-run mode, we can give an answer. + */ + if (!buf) + return 1; + /* only grow if not in place */ if (strbuf_avail(buf) + buf->len < len) strbuf_grow(buf, len - buf->len); @@ -360,12 +376,16 @@ static int filter_buffer(int in, int out, void *data) if (start_command(&child_process)) return error("cannot fork to run external filter %s", params->cmd); + sigchain_push(SIGPIPE, SIG_IGN); + write_err = (write_in_full(child_process.in, params->src, params->size) < 0); if (close(child_process.in)) write_err = 1; if (write_err) error("cannot feed the input to external filter %s", params->cmd); + sigchain_pop(SIGPIPE); + status = finish_command(&child_process); if (status) error("external filter %s failed %d", params->cmd, status); @@ -391,6 +411,9 @@ static int apply_filter(const char *path, const char *src, size_t len, if (!cmd) return 0; + if (!dst) + return 1; + memset(&async, 0, sizeof(async)); async.proc = filter_buffer; async.data = ¶ms; @@ -522,9 +545,12 @@ static int ident_to_git(const char *path, const char *src, size_t len, { char *dst, *dollar; - if (!ident || !count_ident(src, len)) + if (!ident || (src && !count_ident(src, len))) return 0; + if (!buf) + return 1; + /* only grow if not in place */ if (strbuf_avail(buf) + buf->len < len) strbuf_grow(buf, len - buf->len); @@ -641,7 +667,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len, return 1; } -static int git_path_check_crlf(const char *path, struct git_attr_check *check) +static enum crlf_action git_path_check_crlf(const char *path, struct git_attr_check *check) { const char *value = check->value; @@ -658,7 +684,7 @@ static int git_path_check_crlf(const char *path, struct git_attr_check *check) return CRLF_GUESS; } -static int git_path_check_eol(const char *path, struct git_attr_check *check) +static enum eol git_path_check_eol(const char *path, struct git_attr_check *check) { const char *value = check->value; @@ -754,13 +780,13 @@ int convert_to_git(const char *path, const char *src, size_t len, filter = ca.drv->clean; ret |= apply_filter(path, src, len, dst, filter); - if (ret) { + if (ret && dst) { src = dst->buf; len = dst->len; } ca.crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr); ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe); - if (ret) { + if (ret && dst) { src = dst->buf; len = dst->len; } @@ -811,7 +837,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str src = dst->buf; len = dst->len; } - return ret | convert_to_git(path, src, len, dst, 0); + return ret | convert_to_git(path, src, len, dst, SAFE_CRLF_FALSE); } /***************************************************************** @@ -876,43 +902,109 @@ int is_null_stream_filter(struct stream_filter *filter) /* * LF-to-CRLF filter */ + +struct lf_to_crlf_filter { + struct stream_filter filter; + unsigned has_held:1; + char held; +}; + static int lf_to_crlf_filter_fn(struct stream_filter *filter, const char *input, size_t *isize_p, char *output, size_t *osize_p) { - size_t count; + size_t count, o = 0; + struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter; + + /* + * We may be holding onto the CR to see if it is followed by a + * LF, in which case we would need to go to the main loop. + * Otherwise, just emit it to the output stream. + */ + if (lf_to_crlf->has_held && (lf_to_crlf->held != '\r' || !input)) { + output[o++] = lf_to_crlf->held; + lf_to_crlf->has_held = 0; + } + + /* We are told to drain */ + if (!input) { + *osize_p -= o; + return 0; + } - if (!input) - return 0; /* we do not keep any states */ count = *isize_p; - if (count) { - size_t i, o; - for (i = o = 0; o < *osize_p && i < count; i++) { + if (count || lf_to_crlf->has_held) { + size_t i; + int was_cr = 0; + + if (lf_to_crlf->has_held) { + was_cr = 1; + lf_to_crlf->has_held = 0; + } + + for (i = 0; o < *osize_p && i < count; i++) { char ch = input[i]; + if (ch == '\n') { - if (o + 1 < *osize_p) - output[o++] = '\r'; - else - break; + output[o++] = '\r'; + } else if (was_cr) { + /* + * Previous round saw CR and it is not followed + * by a LF; emit the CR before processing the + * current character. + */ + output[o++] = '\r'; + } + + /* + * We may have consumed the last output slot, + * in which case we need to break out of this + * loop; hold the current character before + * returning. + */ + if (*osize_p <= o) { + lf_to_crlf->has_held = 1; + lf_to_crlf->held = ch; + continue; /* break but increment i */ } + + if (ch == '\r') { + was_cr = 1; + continue; + } + + was_cr = 0; output[o++] = ch; } *osize_p -= o; *isize_p -= i; + + if (!lf_to_crlf->has_held && was_cr) { + lf_to_crlf->has_held = 1; + lf_to_crlf->held = '\r'; + } } return 0; } +static void lf_to_crlf_free_fn(struct stream_filter *filter) +{ + free(filter); +} + static struct stream_filter_vtbl lf_to_crlf_vtbl = { lf_to_crlf_filter_fn, - null_free_fn, + lf_to_crlf_free_fn, }; -static struct stream_filter lf_to_crlf_filter_singleton = { - &lf_to_crlf_vtbl, -}; +static struct stream_filter *lf_to_crlf_filter(void) +{ + struct lf_to_crlf_filter *lf_to_crlf = xcalloc(1, sizeof(*lf_to_crlf)); + lf_to_crlf->filter.vtbl = &lf_to_crlf_vtbl; + return (struct stream_filter *)lf_to_crlf; +} /* * Cascade filter @@ -1194,7 +1286,7 @@ struct stream_filter *get_stream_filter(const char *path, const unsigned char *s else if (output_eol(crlf_action) == EOL_CRLF && !(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS)) - filter = cascade_filter(filter, &lf_to_crlf_filter_singleton); + filter = cascade_filter(filter, lf_to_crlf_filter()); return filter; }