diff --git a/diff-lib.c b/diff-lib.c
index 6678e22..9302d2b 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -30,22 +30,61 @@ static int read_directory(const char *path, struct path_list *list)
return 0;
}
-static int queue_diff(struct diff_options *o,
- const char *name1, const char *name2)
+static int get_mode(const char *path, int *mode, int seen_dashdash)
{
struct stat st;
- int mode1 = 0, mode2 = 0;
- if (name1) {
- if (stat(name1, &st))
- return error("Could not access '%s'", name1);
- mode1 = st.st_mode;
+ if (!path)
+ *mode = 0;
+ else if (!seen_dashdash && !strcmp(path, "-"))
+ *mode = 020600;
+ else if (stat(path, &st))
+ return error("Could not access '%s'", path);
+ else
+ *mode = st.st_mode;
+ return 0;
+}
+
+static void read_stdin(void **buffer, unsigned long *size)
+{
+ char *buf = NULL;
+#define INCREMENT 1024
+ int i = INCREMENT;
+
+ *size = 0;
+ buf = NULL;
+ while (i == INCREMENT) {
+ buf = xrealloc(buf, *size + INCREMENT);
+ i = xread(0, buf + *size, INCREMENT);
+ *size += i;
}
- if (name2) {
- if (stat(name2, &st))
- return error("Could not access '%s'", name2);
- mode2 = st.st_mode;
+ *buffer = buf;
+}
+
+static struct diff_filespec *make_diff_filespec(const char *path, int mode)
+{
+ struct diff_filespec *result;
+ if (!path)
+ path = "/dev/null";
+ result = alloc_filespec(path);
+ fill_filespec(result, null_sha1, mode);
+ if (mode == 020600) {
+ read_stdin(&result->data, &result->size);
+ result->mode = 0100644;
+ result->should_munmap = 0;
+ result->should_free = 1;
}
+ return result;
+}
+
+static int queue_diff(struct diff_options *o,
+ const char *name1, const char *name2, int seen_dashdash)
+{
+ int mode1 = 0, mode2 = 0;
+
+ if (get_mode(name1, &mode1, seen_dashdash) ||
+ get_mode(name2, &mode2, seen_dashdash))
+ return -1;
if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2))
return error("file/directory conflict: %s, %s", name1, name2);@@ -106,7 +145,7 @@ static int queue_diff(struct diff_options *o,
PATH_MAX - len2);
}
- ret = queue_diff(o, n1, n2);
+ ret = queue_diff(o, n1, n2, 1);
}
path_list_clear(&p1, 0);
path_list_clear(&p2, 0);
@@ -122,14 +161,8 @@ static int queue_diff(struct diff_options *o,
tmp_c = name1; name1 = name2; name2 = tmp_c;
}
- if (!name1)
- name1 = "/dev/null";
- if (!name2)
- name2 = "/dev/null";
- d1 = alloc_filespec(name1);
- d2 = alloc_filespec(name2);
- fill_filespec(d1, null_sha1, mode1);
- fill_filespec(d2, null_sha1, mode2);
+ d1 = make_diff_filespec(name1, mode1);
+ d2 = make_diff_filespec(name2, mode2);
diff_queue(&diff_queued_diff, d1, d2);
return 0;
@@ -222,11 +255,12 @@ static int is_outside_repo(const char *path, int nongit, const char *prefix)
int setup_diff_no_index(struct rev_info *revs,
int argc, const char ** argv, int nongit, const char *prefix)
{
- int i;
+ int i, seen_dashdash = 0;
for (i = 1; i < argc; i++)
- if (argv[i][0] != '-')
+ if (argv[i][0] != '-' || argv[i][1] == '\0')
break;
else if (!strcmp(argv[i], "--")) {
+ seen_dashdash = 1;
i++;
break;
} else if (i < argc - 3 && !strcmp(argv[i], "--no-index")) {@@ -238,7 +272,7 @@ int setup_diff_no_index(struct rev_info *revs,
return -1;
diff_setup(&revs->diffopt);
- for (i = 1; i < argc - 2; )
+ for (i = 1; i < argc - 2 - seen_dashdash; )
if (!strcmp(argv[i], "--no-index"))
i++;
else {@@ -250,22 +284,26 @@ int setup_diff_no_index(struct rev_info *revs,
}
revs->diffopt.paths = argv + argc - 2;
revs->diffopt.nr_paths = 2;
- revs->max_count = -2;
+ revs->max_count = -2 - seen_dashdash;
return 0;
}
int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
{
- int silent_on_removed;
+ int silent_on_removed, seen_dashdash = 0;
- if (handle_diff_files_args(revs, argc, argv, &silent_on_removed))
+ if (revs->max_count == -3) {
+ seen_dashdash = 1;
+ revs->max_count = -2;
+ } else if (handle_diff_files_args(revs, argc, argv,
+ &silent_on_removed))
return -1;
if (revs->max_count == -2) {
if (revs->diffopt.nr_paths != 2)
return error("need two files/directories with --no-index");
if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
- revs->diffopt.paths[1]))
+ revs->diffopt.paths[1], seen_dashdash))
return -1;
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);--
1.5.0.1.784.g105d9-dirty