author | Lars Hjemli <hjemli@gmail.com> | 2007-05-13 12:21:19 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2007-05-13 12:21:19 (UTC) |
commit | c4ef667961ef4668c9449124f97d55b9ac46c059 (patch) (side-by-side diff) | |
tree | 3e1d3ed9dbf2bac55d0ffbcd2909c5d935fae48b | |
parent | 48dc00342effe3ba530ff6cbb79e5d0d5fc740fd (diff) | |
download | cgit-c4ef667961ef4668c9449124f97d55b9ac46c059.zip cgit-c4ef667961ef4668c9449124f97d55b9ac46c059.tar.gz cgit-c4ef667961ef4668c9449124f97d55b9ac46c059.tar.bz2 |
Add standard interface for file diff functions
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | cgit.h | 7 | ||||
-rw-r--r-- | shared.c | 79 |
2 files changed, 86 insertions, 0 deletions
@@ -11,24 +11,25 @@ #include <tag.h> #include <diff.h> #include <diffcore.h> #include <refs.h> #include <revision.h> #include <log-tree.h> #include <archive.h> #include <xdiff/xdiff.h> typedef void (*configfn)(const char *name, const char *value); typedef void (*filepair_fn)(struct diff_filepair *pair); +typedef void (*linediff_fn)(char *line, int len); struct cacheitem { char *name; struct stat st; int ttl; int fd; }; struct repoinfo { char *url; char *name; char *path; @@ -108,27 +109,33 @@ extern int cgit_query_ofs; extern int htmlfd; extern void cgit_global_config_cb(const char *name, const char *value); extern void cgit_repo_config_cb(const char *name, const char *value); extern void cgit_querystring_cb(const char *name, const char *value); extern int chk_zero(int result, char *msg); extern int chk_positive(int result, char *msg); extern int hextoint(char c); extern void *cgit_free_commitinfo(struct commitinfo *info); + +extern int cgit_diff_files(const unsigned char *old_sha1, + const unsigned char *new_sha1, + linediff_fn fn); + extern void cgit_diff_tree(const unsigned char *old_sha1, const unsigned char *new_sha1, filepair_fn fn); + extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); extern char *fmt(const char *format,...); extern void html(const char *txt); extern void htmlf(const char *format,...); extern void html_txt(char *txt); extern void html_ntxt(int len, char *txt); extern void html_attr(char *txt); extern void html_hidden(char *name, char *value); extern void html_link_open(char *url, char *title, char *class); extern void html_link_close(void); @@ -198,24 +198,103 @@ int hextoint(char c) void cgit_diff_tree_cb(struct diff_queue_struct *q, struct diff_options *options, void *data) { int i; for (i = 0; i < q->nr; i++) { if (q->queue[i]->status == 'U') continue; ((filepair_fn)data)(q->queue[i]); } } +static int load_mmfile(mmfile_t *file, const unsigned char *sha1) +{ + enum object_type type; + + if (is_null_sha1(sha1)) { + file->ptr = (char *)""; + file->size = 0; + } else { + file->ptr = read_sha1_file(sha1, &type, &file->size); + } + return 1; +} + +/* + * Receive diff-buffers from xdiff and concatenate them as + * needed across multiple callbacks. + * + * This is basically a copy of xdiff-interface.c/xdiff_outf(), + * ripped from git and modified to use globals instead of + * a special callback-struct. + */ +char *diffbuf = NULL; +int buflen = 0; + +int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf) +{ + int i; + + for (i = 0; i < nbuf; i++) { + if (mb[i].ptr[mb[i].size-1] != '\n') { + /* Incomplete line */ + diffbuf = xrealloc(diffbuf, buflen + mb[i].size); + memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); + buflen += mb[i].size; + continue; + } + + /* we have a complete line */ + if (!diffbuf) { + ((linediff_fn)priv)(mb[i].ptr, mb[i].size); + continue; + } + diffbuf = xrealloc(diffbuf, buflen + mb[i].size); + memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); + ((linediff_fn)priv)(diffbuf, buflen + mb[i].size); + free(diffbuf); + diffbuf = NULL; + buflen = 0; + } + if (diffbuf) { + ((linediff_fn)priv)(diffbuf, buflen); + free(diffbuf); + diffbuf = NULL; + buflen = 0; + } + return 0; +} + +int cgit_diff_files(const unsigned char *old_sha1, + const unsigned char *new_sha1, + linediff_fn fn) +{ + mmfile_t file1, file2; + xpparam_t diff_params; + xdemitconf_t emit_params; + xdemitcb_t emit_cb; + + if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1)) + return 1; + + diff_params.flags = XDF_NEED_MINIMAL; + emit_params.ctxlen = 3; + emit_params.flags = XDL_EMIT_FUNCNAMES; + emit_cb.outf = filediff_cb; + emit_cb.priv = fn; + xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); + return 0; +} + void cgit_diff_tree(const unsigned char *old_sha1, const unsigned char *new_sha1, filepair_fn fn) { struct diff_options opt; int ret; diff_setup(&opt); opt.output_format = DIFF_FORMAT_CALLBACK; opt.detect_rename = 1; opt.recursive = 1; opt.format_callback = cgit_diff_tree_cb; |