diff options
author | Russell Belfer <rb@github.com> | 2013-08-26 23:17:07 -0700 |
---|---|---|
committer | Russell Belfer <rb@github.com> | 2013-09-17 09:30:06 -0700 |
commit | 0cf77103b218ad3622aff34f3296db1bdd5f0df9 (patch) | |
tree | f60998088c2617f3a289942d7928112f0fe683e9 /src | |
parent | 4581f9d8ab72e9b97817e1eaa7154bcec1c7f0b1 (diff) | |
download | libgit2-0cf77103b218ad3622aff34f3296db1bdd5f0df9.tar.gz |
Start of filter API + git_blob_filtered_content
This begins the process of exposing git_filter objects to the
public API. This includes:
* new public type and API for `git_buffer` through which an
allocated buffer can be passed to the user
* new API `git_blob_filtered_content`
* make the git_filter type and GIT_FILTER_TO_... constants public
Diffstat (limited to 'src')
-rw-r--r-- | src/blob.c | 51 | ||||
-rw-r--r-- | src/buf_text.c | 19 | ||||
-rw-r--r-- | src/buf_text.h | 8 | ||||
-rw-r--r-- | src/buffer.c | 54 | ||||
-rw-r--r-- | src/crlf.c | 20 | ||||
-rw-r--r-- | src/filter.h | 19 |
6 files changed, 141 insertions, 30 deletions
diff --git a/src/blob.c b/src/blob.c index 6a289f43b..6a866538c 100644 --- a/src/blob.c +++ b/src/blob.c @@ -338,3 +338,54 @@ int git_blob_is_binary(git_blob *blob) return git_buf_text_is_binary(&content); } + +int git_blob_filtered_content( + git_buffer *out, + git_blob *blob, + const char *as_path, + int check_for_binary_data) +{ + int error = 0, num_filters = 0; + git_buf filtered = GIT_BUF_INIT, unfiltered = GIT_BUF_INIT; + git_vector filters = GIT_VECTOR_INIT; + + assert(blob && as_path && out); + + /* Create a fake git_buf from the blob raw data... */ + filtered.ptr = (void *)git_blob_rawcontent(blob); + filtered.size = (size_t)git_blob_rawsize(blob); + filtered.asize = 0; + + if (check_for_binary_data && git_buf_text_is_binary(&filtered)) + return 0; + + num_filters = git_filters_load( + &filters, git_blob_owner(blob), as_path, GIT_FILTER_TO_WORKTREE); + if (num_filters < 0) + return num_filters; + + if (num_filters > 0) { + if (out->ptr && out->available) { + filtered.ptr = out->ptr; + filtered.size = out->size; + filtered.asize = out->available; + } else { + git_buf_init(&filtered, filtered.size + 1); + } + + if (!(error = git_blob__getbuf(&unfiltered, blob))) + error = git_filters_apply(&filtered, &unfiltered, &filters); + + git_filters_free(&filters); + git_buf_free(&unfiltered); + } + + if (!error) { + out->ptr = filtered.ptr; + out->size = filtered.size; + out->available = filtered.asize; + } + + return error; +} + diff --git a/src/buf_text.c b/src/buf_text.c index ecf592b51..eda86adb3 100644 --- a/src/buf_text.c +++ b/src/buf_text.c @@ -70,10 +70,10 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src) assert(tgt != src); if (!next) - return GIT_ENOTFOUND; + return git_buf_set(tgt, src->ptr, src->size); /* reduce reallocs while in the loop */ - if (git_buf_grow(tgt, src->size) < 0) + if (git_buf_grow(tgt, src->size + 1) < 0) return -1; out = tgt->ptr; tgt->size = 0; @@ -81,7 +81,7 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src) /* Find the next \r and copy whole chunk up to there to tgt */ for (; next; scan = next + 1, next = memchr(scan, '\r', scan_end - scan)) { if (next > scan) { - size_t copylen = next - scan; + size_t copylen = (size_t)(next - scan); memcpy(out, scan, copylen); out += copylen; } @@ -92,9 +92,14 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src) } /* Copy remaining input into dest */ - memcpy(out, scan, scan_end - scan + 1); /* +1 for NUL byte */ - out += (scan_end - scan); - tgt->size = out - tgt->ptr; + if (scan < scan_end) { + size_t remaining = (size_t)(scan_end - scan); + memcpy(out, scan, remaining); + out += remaining; + } + + tgt->size = (size_t)(out - tgt->ptr); + tgt->ptr[tgt->size] = '\0'; return 0; } @@ -109,7 +114,7 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src) assert(tgt != src); if (!next) - return GIT_ENOTFOUND; + return git_buf_set(tgt, src->ptr, src->size); /* attempt to reduce reallocs while in the loop */ if (git_buf_grow(tgt, src->size + (src->size >> 4) + 1) < 0) diff --git a/src/buf_text.h b/src/buf_text.h index 58e4e26a7..3ac9d1443 100644 --- a/src/buf_text.h +++ b/src/buf_text.h @@ -56,16 +56,16 @@ GIT_INLINE(int) git_buf_text_puts_escape_regex(git_buf *buf, const char *string) extern void git_buf_text_unescape(git_buf *buf); /** - * Replace all \r\n with \n (or do nothing if no \r\n are found) + * Replace all \r\n with \n. Does not modify \r without trailing \n. * - * @return 0 on success, GIT_ENOTFOUND if no \r\n, -1 on memory error + * @return 0 on success, -1 on memory error */ extern int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src); /** - * Replace all \n with \r\n (or do nothing if no \n are found) + * Replace all \n with \r\n. Does not modify existing \r\n. * - * @return 0 on success, GIT_ENOTFOUND if no \n, -1 on memory error + * @return 0 on success, -1 on memory error */ extern int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src); diff --git a/src/buffer.c b/src/buffer.c index b5b2fd678..a92133674 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -6,6 +6,7 @@ */ #include "buffer.h" #include "posix.h" +#include "git2/buffer.h" #include <stdarg.h> #include <ctype.h> @@ -484,3 +485,56 @@ int git_buf_splice( buf->ptr[buf->size] = '\0'; return 0; } + +/* + * Public buffers API + */ + +void git_buffer_free(git_buffer *buffer) +{ + if (!buffer) + return; + + if (buffer->ptr != NULL && buffer->available > 0) + git__free(buffer->ptr); + + git__memzero(buffer, sizeof(*buffer)); +} + +int git_buffer_resize(git_buffer *buffer, size_t want_size) +{ + int non_allocated_buffer = 0; + char *new_ptr; + + assert(buffer); + + /* check if buffer->ptr points to memory owned elsewhere */ + non_allocated_buffer = (buffer->ptr != NULL && buffer->available == 0); + + if (non_allocated_buffer && !want_size) + want_size = buffer->size; + + if (buffer->available <= want_size) + return 0; + + if (non_allocated_buffer) { + new_ptr = NULL; + if (want_size < buffer->size) + want_size = buffer->size; + } else { + new_ptr = buffer->ptr; + } + + want_size = (want_size + 7) & ~7; /* round up to multiple of 8 */ + + new_ptr = git__realloc(new_ptr, want_size); + GITERR_CHECK_ALLOC(new_ptr); + + if (non_allocated_buffer) + memcpy(new_ptr, buffer->ptr, buffer->size); + + buffer->ptr = new_ptr; + buffer->available = want_size; + + return 0; +} diff --git a/src/crlf.c b/src/crlf.c index 65039f9cc..fbb3ba2dd 100644 --- a/src/crlf.c +++ b/src/crlf.c @@ -235,32 +235,36 @@ line_ending_error: } static int crlf_apply_to_workdir( - git_filter *self, git_buf *dest, const git_buf *source) + git_filter *self, git_buf *tgt, const git_buf *src) { struct crlf_filter *filter = (struct crlf_filter *)self; const char *workdir_ending = NULL; - assert(self && dest && source); + assert(self && tgt && src); /* Empty file? Nothing to do. */ - if (git_buf_len(source) == 0) + if (git_buf_len(src) == 0) return -1; /* Determine proper line ending */ workdir_ending = line_ending(filter); if (!workdir_ending) return -1; - if (!strcmp("\n", workdir_ending)) /* do nothing for \n ending */ - return -1; - /* for now, only lf->crlf conversion is supported here */ + if (!strcmp("\n", workdir_ending)) { + if (git_buf_find(src, '\r') < 0) + return -1; + return git_buf_text_crlf_to_lf(tgt, src); + } + + /* only other supported option is lf->crlf conversion */ assert(!strcmp("\r\n", workdir_ending)); - return git_buf_text_lf_to_crlf(dest, source); + return git_buf_text_lf_to_crlf(tgt, src); } static int find_and_add_filter( git_vector *filters, git_repository *repo, const char *path, - int (*apply)(struct git_filter *self, git_buf *dest, const git_buf *source)) + int (*apply)(struct git_filter *self, git_buf *tgt, const git_buf *src)) { struct crlf_attrs ca; struct crlf_filter *filter; diff --git a/src/filter.h b/src/filter.h index 42a44ebdb..67845ad6a 100644 --- a/src/filter.h +++ b/src/filter.h @@ -11,16 +11,12 @@ #include "buffer.h" #include "git2/odb.h" #include "git2/repository.h" +#include "git2/filter.h" -typedef struct git_filter { +struct git_filter { int (*apply)(struct git_filter *self, git_buf *dest, const git_buf *source); void (*do_free)(struct git_filter *self); -} git_filter; - -typedef enum { - GIT_FILTER_TO_WORKTREE, - GIT_FILTER_TO_ODB -} git_filter_mode; +}; typedef enum { GIT_CRLF_GUESS = -1, @@ -60,13 +56,14 @@ extern int git_filters_load(git_vector *filters, git_repository *repo, const cha * and `dest` buffers are owned by the caller and must be freed once * they are no longer needed. * - * NOTE: Because of the double-buffering schema, the `source` buffer that contains - * the original file may be tampered once the filtering is complete. Regardless, - * the `dest` buffer will always contain the final result of the filtering + * NOTE: Because of the double-buffering schema, the `source` buffer that + * contains the original file may be tampered once the filtering is + * complete. Regardless, the `dest` buffer will always contain the final + * result of the filtering * * @param dest Buffer to store the result of the filtering * @param source Buffer containing the document to filter - * @param filters A non-empty vector of filters as supplied by `git_filters_load` + * @param filters Vector of filters as supplied by `git_filters_load` * @return 0 on success, an error code otherwise */ extern int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters); |