diff options
author | Vicent Martà <tanoku@gmail.com> | 2012-03-02 00:19:51 +0400 |
---|---|---|
committer | Vicent Martà <tanoku@gmail.com> | 2012-03-02 00:19:51 +0400 |
commit | 47a899ffed3c71080e10e73eda092a716f1be168 (patch) | |
tree | 181f4f0b52318fbe65fbd9aa3079593533d45715 /src/crlf.c | |
parent | 788430c8e3fa90dd965b44fb31ba8b2eece2ca37 (diff) |
filter: Beautiful refactoring
Comments soothe my soul.
Diffstat (limited to 'src/crlf.c')
-rw-r--r-- | src/crlf.c | 116 |
1 files changed, 82 insertions, 34 deletions
diff --git a/src/crlf.c b/src/crlf.c index d8dd1c382..feaa687ee 100644 --- a/src/crlf.c +++ b/src/crlf.c @@ -102,18 +102,74 @@ static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, con return error; } -static int crlf_apply_to_odb(git_filter *self, git_buf *dest, const git_buf *source) +static int drop_crlf(git_buf *dest, const git_buf *source) { + size_t psize = source->size - 1; size_t i = 0; + + /* Initial scan: see if we can reach the end of the document + * without finding a single carriage return */ + while (i < psize && source->ptr[i] != '\r') + i++; + + /* Clean file? Tell the library to skip this filter */ + if (i == psize) + return -1; + + /* Main scan loop. Keep moving forward until we find a carriage + * return, and then copy the whole chunk to the destination + * buffer. + * + * Note that we only scan until `size - 1`, because we cannot drop a + * carriage return if it's the last character in the file (what a weird + * file, anyway) + */ + while (i < psize) { + size_t org = i; + + while (i < psize && source->ptr[i] != '\r') + i++; + + if (i > org) + git_buf_put(dest, source->ptr + org, i - org); + + /* We found a carriage return. Is the next character a newline? + * If it is, we just keep moving. The newline will be copied + * to the dest in the next chunk. + * + * If it's not a newline, we need to insert the carriage return + * into the dest buffer, because we don't drop lone CRs. + */ + if (source->ptr[i + 1] != '\n') { + git_buf_putc(dest, '\r'); + } + + i++; + } + + /* Copy the last character in the file */ + git_buf_putc(dest, source->ptr[psize]); + return 0; +} + +static int crlf_apply_to_odb(git_filter *self, git_buf *dest, const git_buf *source) +{ struct crlf_filter *filter = (struct crlf_filter *)self; assert(self && dest && source); + /* Empty file? Nothing to do */ + if (source->size == 0) + return 0; + + /* Heuristics to see if we can skip the conversion. + * Straight from Core Git. + */ if (filter->attrs.crlf_action == GIT_CRLF_AUTO || filter->attrs.crlf_action == GIT_CRLF_GUESS) { git_text_stats stats; - git_text__stat(&stats, source); + git_text_gather_stats(&stats, source); /* * We're currently not going to even try to convert stuff @@ -126,7 +182,7 @@ static int crlf_apply_to_odb(git_filter *self, git_buf *dest, const git_buf *sou /* * And add some heuristics for binary vs text, of course... */ - if (git_text__is_binary(&stats)) + if (git_text_is_binary(&stats)) return -1; #if 0 @@ -144,50 +200,42 @@ static int crlf_apply_to_odb(git_filter *self, git_buf *dest, const git_buf *sou return -1; } - /* TODO: do not copy anything if there isn't a single CR */ - while (i < source->size) { - size_t org = i; - - while (i < source->size && source->ptr[i] != '\r') - i++; - - if (i > org) - git_buf_put(dest, source->ptr + org, i - org); - - i++; - - if (i >= source->size || source->ptr[i] != '\n') { - git_buf_putc(dest, '\r'); - } - } - - return 0; + /* Actually drop the carriage returns */ + return drop_crlf(dest, source); } -int git_filter__crlf_to_odb(git_filter **filter_out, git_repository *repo, const char *path) +int git_filter_add__crlf_to_odb(git_vector *filters, git_repository *repo, const char *path) { - struct crlf_filter filter; + struct crlf_attrs ca; + struct crlf_filter *filter; int error; - filter.f.apply = &crlf_apply_to_odb; - filter.f.do_free = NULL; - - if ((error = crlf_load_attributes(&filter.attrs, repo, path)) < 0) + /* Load gitattributes for the path */ + if ((error = crlf_load_attributes(&ca, repo, path)) < 0) return error; - filter.attrs.crlf_action = crlf_input_action(&filter.attrs); + /* + * Use the core Git logic to see if we should perform CRLF for this file + * based on its attributes & the value of `core.auto_crlf` + */ + ca.crlf_action = crlf_input_action(&ca); - if (filter.attrs.crlf_action == GIT_CRLF_BINARY) + if (ca.crlf_action == GIT_CRLF_BINARY) return 0; - if (filter.attrs.crlf_action == GIT_CRLF_GUESS && repo->filter_options.auto_crlf == GIT_AUTO_CRLF_FALSE) + if (ca.crlf_action == GIT_CRLF_GUESS && repo->filter_options.auto_crlf == GIT_AUTO_CRLF_FALSE) return 0; - *filter_out = git__malloc(sizeof(struct crlf_filter)); - if (*filter_out == NULL) + /* If we're good, we create a new filter object and push it + * into the filters array */ + filter = git__malloc(sizeof(struct crlf_filter)); + if (filter == NULL) return GIT_ENOMEM; - memcpy(*filter_out, &filter, sizeof(struct crlf_attrs)); - return 0; + filter->f.apply = &crlf_apply_to_odb; + filter->f.do_free = NULL; + memcpy(&filter->attrs, &ca, sizeof(struct crlf_attrs)); + + return git_vector_insert(filters, filter); } |