Commit 3be09b6c by Alberto Fanjul

Compare buffers in diff example

parent 398412cc
...@@ -14,6 +14,14 @@ ...@@ -14,6 +14,14 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _WIN32
# include <io.h>
#else
# include <fcntl.h>
# include <unistd.h>
#endif
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
...@@ -391,3 +399,37 @@ out: ...@@ -391,3 +399,37 @@ out:
free(pubkey); free(pubkey);
return error; return error;
} }
char *read_file(const char *path)
{
ssize_t total = 0;
char *buf = NULL;
struct stat st;
int fd = -1;
if ((fd = open(path, O_RDONLY)) < 0 || fstat(fd, &st) < 0)
goto out;
if ((buf = malloc(st.st_size + 1)) == NULL)
goto out;
while (total < st.st_size) {
ssize_t bytes = read(fd, buf + total, st.st_size - total);
if (bytes <= 0) {
if (errno == EAGAIN || errno == EINTR)
continue;
free(buf);
buf = NULL;
goto out;
}
total += bytes;
}
buf[total] = '\0';
out:
if (fd >= 0)
close(fd);
return buf;
}
...@@ -64,6 +64,14 @@ extern int lg2_tag(git_repository *repo, int argc, char **argv); ...@@ -64,6 +64,14 @@ extern int lg2_tag(git_repository *repo, int argc, char **argv);
extern void check_lg2(int error, const char *message, const char *extra); extern void check_lg2(int error, const char *message, const char *extra);
/** /**
* Read a file into a buffer
*
* @param path The path to the file that shall be read
* @return NUL-terminated buffer if the file was successfully read, NULL-pointer otherwise
*/
extern char *read_file(const char *path);
/**
* Exit the program, printing error to stderr * Exit the program, printing error to stderr
*/ */
extern void fatal(const char *message, const char *extra); extern void fatal(const char *message, const char *extra);
...@@ -89,7 +97,7 @@ struct args_info { ...@@ -89,7 +97,7 @@ struct args_info {
/** /**
* Check current `args` entry against `opt` string. If it matches * Check current `args` entry against `opt` string. If it matches
* exactly, take the next arg as a string; if it matches as a prefix with * exactly, take the next arg as a string; if it matches as a prefix with
* an equal sign, take the remainder as a string; if value not supplied, * an equal sign, take the remainder as a string; if value not supplied,
* default value `def` will be given. otherwise return 0. * default value `def` will be given. otherwise return 0.
*/ */
extern int optional_str_arg( extern int optional_str_arg(
......
...@@ -52,6 +52,7 @@ struct opts { ...@@ -52,6 +52,7 @@ struct opts {
git_diff_options diffopts; git_diff_options diffopts;
git_diff_find_options findopts; git_diff_find_options findopts;
int color; int color;
int no_index;
int cache; int cache;
int output; int output;
git_diff_format_t format; git_diff_format_t format;
...@@ -66,14 +67,16 @@ static void parse_opts(struct opts *o, int argc, char *argv[]); ...@@ -66,14 +67,16 @@ static void parse_opts(struct opts *o, int argc, char *argv[]);
static int color_printer( static int color_printer(
const git_diff_delta*, const git_diff_hunk*, const git_diff_line*, void*); const git_diff_delta*, const git_diff_hunk*, const git_diff_line*, void*);
static void diff_print_stats(git_diff *diff, struct opts *o); static void diff_print_stats(git_diff *diff, struct opts *o);
static void compute_diff_no_index(git_diff **diff, struct opts *o);
int lg2_diff(git_repository *repo, int argc, char *argv[]) int lg2_diff(git_repository *repo, int argc, char *argv[])
{ {
git_tree *t1 = NULL, *t2 = NULL; git_tree *t1 = NULL, *t2 = NULL;
git_diff *diff; git_diff *diff;
struct opts o = { struct opts o = {
GIT_DIFF_OPTIONS_INIT, GIT_DIFF_FIND_OPTIONS_INIT, GIT_DIFF_OPTIONS_INIT, GIT_DIFF_FIND_OPTIONS_INIT,
-1, 0, 0, GIT_DIFF_FORMAT_PATCH, NULL, NULL, "." -1, -1, 0, 0, GIT_DIFF_FORMAT_PATCH, NULL, NULL, "."
}; };
parse_opts(&o, argc, argv); parse_opts(&o, argc, argv);
...@@ -86,49 +89,54 @@ int lg2_diff(git_repository *repo, int argc, char *argv[]) ...@@ -86,49 +89,54 @@ int lg2_diff(git_repository *repo, int argc, char *argv[])
* * &lt;sha1&gt; * * &lt;sha1&gt;
* * --cached * * --cached
* * --nocache (don't use index data in diff at all) * * --nocache (don't use index data in diff at all)
* * --no-index &lt;file1&gt; &lt;file2&gt;
* * nothing * * nothing
* *
* Currently ranged arguments like &lt;sha1&gt;..&lt;sha2&gt; and &lt;sha1&gt;...&lt;sha2&gt; * Currently ranged arguments like &lt;sha1&gt;..&lt;sha2&gt; and &lt;sha1&gt;...&lt;sha2&gt;
* are not supported in this example * are not supported in this example
*/ */
if (o.treeish1) if (o.no_index >= 0) {
treeish_to_tree(&t1, repo, o.treeish1); compute_diff_no_index(&diff, &o);
if (o.treeish2) } else {
treeish_to_tree(&t2, repo, o.treeish2); if (o.treeish1)
treeish_to_tree(&t1, repo, o.treeish1);
if (t1 && t2) if (o.treeish2)
check_lg2( treeish_to_tree(&t2, repo, o.treeish2);
git_diff_tree_to_tree(&diff, repo, t1, t2, &o.diffopts),
"diff trees", NULL);
else if (o.cache != CACHE_NORMAL) {
if (!t1)
treeish_to_tree(&t1, repo, "HEAD");
if (o.cache == CACHE_NONE) if (t1 && t2)
check_lg2(
git_diff_tree_to_tree(&diff, repo, t1, t2, &o.diffopts),
"diff trees", NULL);
else if (o.cache != CACHE_NORMAL) {
if (!t1)
treeish_to_tree(&t1, repo, "HEAD");
if (o.cache == CACHE_NONE)
check_lg2(
git_diff_tree_to_workdir(&diff, repo, t1, &o.diffopts),
"diff tree to working directory", NULL);
else
check_lg2(
git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts),
"diff tree to index", NULL);
}
else if (t1)
check_lg2( check_lg2(
git_diff_tree_to_workdir(&diff, repo, t1, &o.diffopts), git_diff_tree_to_workdir_with_index(&diff, repo, t1, &o.diffopts),
"diff tree to working directory", NULL); "diff tree to working directory", NULL);
else else
check_lg2( check_lg2(
git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts), git_diff_index_to_workdir(&diff, repo, NULL, &o.diffopts),
"diff tree to index", NULL); "diff index to working directory", NULL);
}
else if (t1)
check_lg2(
git_diff_tree_to_workdir_with_index(&diff, repo, t1, &o.diffopts),
"diff tree to working directory", NULL);
else
check_lg2(
git_diff_index_to_workdir(&diff, repo, NULL, &o.diffopts),
"diff index to working directory", NULL);
/** Apply rename and copy detection if requested. */ /** Apply rename and copy detection if requested. */
if ((o.findopts.flags & GIT_DIFF_FIND_ALL) != 0) if ((o.findopts.flags & GIT_DIFF_FIND_ALL) != 0)
check_lg2( check_lg2(
git_diff_find_similar(diff, &o.findopts), git_diff_find_similar(diff, &o.findopts),
"finding renames and copies", NULL); "finding renames and copies", NULL);
}
/** Generate simple output using libgit2 display helper. */ /** Generate simple output using libgit2 display helper. */
...@@ -158,6 +166,38 @@ int lg2_diff(git_repository *repo, int argc, char *argv[]) ...@@ -158,6 +166,38 @@ int lg2_diff(git_repository *repo, int argc, char *argv[])
return 0; return 0;
} }
static void compute_diff_no_index(git_diff **diff, struct opts *o) {
git_patch *patch = NULL;
char *file1_str = NULL;
char *file2_str = NULL;
git_buf buf = {0};
if (!o->treeish1 || !o->treeish2) {
usage("two files should be provided as arguments", NULL);
}
file1_str = read_file(o->treeish1);
if (file1_str == NULL) {
usage("file cannot be read", o->treeish1);
}
file2_str = read_file(o->treeish2);
if (file2_str == NULL) {
usage("file cannot be read", o->treeish2);
}
check_lg2(
git_patch_from_buffers(&patch, file1_str, strlen(file1_str), o->treeish1, file2_str, strlen(file2_str), o->treeish2, &o->diffopts),
"patch buffers", NULL);
check_lg2(
git_patch_to_buf(&buf, patch),
"patch to buf", NULL);
check_lg2(
git_diff_from_buffer(diff, buf.ptr, buf.size),
"diff from patch", NULL);
git_patch_free(patch);
git_buf_dispose(&buf);
free(file1_str);
free(file2_str);
}
static void usage(const char *message, const char *arg) static void usage(const char *message, const char *arg)
{ {
if (message && arg) if (message && arg)
...@@ -223,9 +263,10 @@ static void parse_opts(struct opts *o, int argc, char *argv[]) ...@@ -223,9 +263,10 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
o->output |= OUTPUT_DIFF; o->output |= OUTPUT_DIFF;
o->format = GIT_DIFF_FORMAT_PATCH; o->format = GIT_DIFF_FORMAT_PATCH;
} }
else if (!strcmp(a, "--cached")) else if (!strcmp(a, "--cached")) {
o->cache = CACHE_ONLY; o->cache = CACHE_ONLY;
else if (!strcmp(a, "--nocache")) if (o->no_index >= 0) usage("--cached and --no-index are incompatible", NULL);
} else if (!strcmp(a, "--nocache"))
o->cache = CACHE_NONE; o->cache = CACHE_NONE;
else if (!strcmp(a, "--name-only") || !strcmp(a, "--format=name")) else if (!strcmp(a, "--name-only") || !strcmp(a, "--format=name"))
o->format = GIT_DIFF_FORMAT_NAME_ONLY; o->format = GIT_DIFF_FORMAT_NAME_ONLY;
...@@ -238,7 +279,10 @@ static void parse_opts(struct opts *o, int argc, char *argv[]) ...@@ -238,7 +279,10 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
o->format = GIT_DIFF_FORMAT_RAW; o->format = GIT_DIFF_FORMAT_RAW;
o->diffopts.id_abbrev = 40; o->diffopts.id_abbrev = 40;
} }
else if (!strcmp(a, "--color")) else if (!strcmp(a, "--no-index")) {
o->no_index = 0;
if (o->cache == CACHE_ONLY) usage("--cached and --no-index are incompatible", NULL);
} else if (!strcmp(a, "--color"))
o->color = 0; o->color = 0;
else if (!strcmp(a, "--no-color")) else if (!strcmp(a, "--no-color"))
o->color = -1; o->color = -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment