diff options
author | Russell Belfer <rb@github.com> | 2013-08-29 03:44:04 +0400 |
---|---|---|
committer | Russell Belfer <rb@github.com> | 2013-09-17 20:30:06 +0400 |
commit | 85d5481206a932d747b2d5587b6d4c7f69993ba6 (patch) | |
tree | a66d55c92d70668509efce5b231517467a3f8b7e /src/filter.c | |
parent | 0cf77103b218ad3622aff34f3296db1bdd5f0df9 (diff) |
Create public filter object and use it
This creates include/sys/filter.h with a basic definition of a
git_filter and then converts the internal code to use it. There
are related internal objects (git_filter_list) that we will want
to publish at some point, but this is a first step.
Diffstat (limited to 'src/filter.c')
-rw-r--r-- | src/filter.c | 176 |
1 files changed, 143 insertions, 33 deletions
diff --git a/src/filter.c b/src/filter.c index 9f749dcbd..7935e6518 100644 --- a/src/filter.c +++ b/src/filter.c @@ -13,62 +13,155 @@ #include "git2/config.h" #include "blob.h" -int git_filters_load(git_vector *filters, git_repository *repo, const char *path, int mode) +typedef struct { + git_filter *filter; + void *payload; +} git_filter_entry; + +struct git_filter_list { + git_array_t(git_filter_entry) filters; + git_filter_mode_t mode; + git_filter_source source; + char path[GIT_FLEX_ARRAY]; +}; + +typedef struct { + const char *filter_name; + git_filter *filter; +} git_filter_def; + +static git_array_t(git_filter_def) filter_registry = GIT_ARRAY_INIT; + +static int filter_load_defaults(void) { - int error; - - if (mode == GIT_FILTER_TO_ODB) { - /* Load the CRLF cleanup filter when writing to the ODB */ - error = git_filter_add__crlf_to_odb(filters, repo, path); - if (error < 0) - return error; - } else { - error = git_filter_add__crlf_to_workdir(filters, repo, path); - if (error < 0) - return error; + if (!git_array_size(filter_registry)) { + git_filter_def *fdef = git_array_alloc(filter_registry); + GITERR_CHECK_ALLOC(fdef); + + fdef->filter_name = GIT_FILTER_CRLF; + fdef->filter = git_crlf_filter_new(); + GITERR_CHECK_ALLOC(fdef->filter); } - return (int)filters->length; + return 0; } -void git_filters_free(git_vector *filters) +static int git_filter_list_new( + git_filter_list **out, git_filter_mode_t mode, const git_filter_source *src) { - size_t i; - git_filter *filter; + git_filter_list *fl = NULL; + size_t pathlen = src->path ? strlen(src->path) : 0; + + fl = git__calloc(1, sizeof(git_filter_list) + pathlen + 1); + GITERR_CHECK_ALLOC(fl); + + fl->mode = mode; + if (src->path) + memcpy(fl->path, src->path, pathlen); + fl->source.repo = src->repo; + fl->source.path = fl->path; + + *out = fl; + return 0; +} + +int git_filter_list_load( + git_filter_list **filters, + git_repository *repo, + const char *path, + git_filter_mode_t mode) +{ + int error = 0; + git_filter_list *fl = NULL; + git_filter_source src = { 0 }; + git_filter_entry *fe; + uint32_t f; + + if (filter_load_defaults() < 0) + return -1; + + src.repo = repo; + src.path = path; + + for (f = 0; f < git_array_size(filter_registry); ++f) { + void *payload = NULL; + git_filter_def *fdef = git_array_get(filter_registry, f); + + if (!fdef || !fdef->filter) + continue; - git_vector_foreach(filters, i, filter) { - if (filter->do_free != NULL) - filter->do_free(filter); - else - git__free(filter); + if (fdef->filter->check) + error = fdef->filter->check(fdef->filter, &payload, mode, &src); + + if (error == GIT_ENOTFOUND) + error = 0; + else if (error < 0) + break; + else { + if (!fl && (error = git_filter_list_new(&fl, mode, &src)) < 0) + return error; + + fe = git_array_alloc(fl->filters); + GITERR_CHECK_ALLOC(fe); + fe->filter = fdef->filter; + fe->payload = payload; + } + } + + if (error && fl != NULL) { + git_array_clear(fl->filters); + git__free(fl); + fl = NULL; + } + + *filters = fl; + return error; +} + +void git_filter_list_free(git_filter_list *fl) +{ + uint32_t i; + + if (!fl) + return; + + for (i = 0; i < git_array_size(fl->filters); ++i) { + git_filter_entry *fe = git_array_get(fl->filters, i); + if (fe->filter->cleanup) + fe->filter->cleanup(fe->filter, fe->payload); } - git_vector_free(filters); + git_array_clear(fl->filters); + git__free(fl); } -int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters) +int git_filter_list_apply( + git_buf *dest, + git_buf *source, + git_filter_list *fl) { - size_t i; + int error = 0; + uint32_t i; unsigned int src; git_buf *dbuffer[2]; + if (!fl) { + git_buf_swap(dest, source); + return 0; + } + dbuffer[0] = source; dbuffer[1] = dest; src = 0; - if (git_buf_len(source) == 0) { - git_buf_clear(dest); - return 0; - } - /* Pre-grow the destination buffer to more or less the size * we expect it to have */ if (git_buf_grow(dest, git_buf_len(source)) < 0) return -1; - for (i = 0; i < filters->length; ++i) { - git_filter *filter = git_vector_get(filters, i); + for (i = 0; i < git_array_size(fl->filters); ++i) { + git_filter_entry *fe = git_array_get(fl->filters, i); unsigned int dst = 1 - src; git_buf_clear(dbuffer[dst]); @@ -79,8 +172,25 @@ int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters) * of the double buffering (so that the text goes through * cleanly). */ - if (filter->apply(filter, dbuffer[dst], dbuffer[src]) == 0) - src = dst; + { + git_buffer srcb = GIT_BUFFER_FROM_BUF(dbuffer[src]); + git_buffer dstb = GIT_BUFFER_FROM_BUF(dbuffer[dst]); + + error = fe->filter->apply( + fe->filter, &fe->payload, fl->mode, &dstb, &srcb, &fl->source); + + if (error == GIT_ENOTFOUND) + error = 0; + else if (error < 0) { + git_buf_clear(dest); + return error; + } + else { + git_buf_from_buffer(dbuffer[src], &srcb); + git_buf_from_buffer(dbuffer[dst], &dstb); + src = dst; + } + } if (git_buf_oom(dbuffer[dst])) return -1; |