+static void call_diff_setup(void)
+{
+ diff_setup(diff_setup_opt);
+}
+
+static int call_diff_flush(void)
+{
+ if (detect_rename)
+ diffcore_rename(detect_rename, diff_score_opt);
+ if (pickaxe)
+ diffcore_pickaxe(pickaxe, pickaxe_opts);
+ if (diff_queue_is_empty()) {
+ diff_flush(DIFF_FORMAT_NO_OUTPUT, 0);
+ return 0;
+ }
+ if (header) {
+ const char *fmt = "%s";
+ if (diff_output_format == DIFF_FORMAT_MACHINE)
+ fmt = "%s%c";
+
+ printf(fmt, header, 0);
+ header = NULL;
+ }
+ diff_flush(diff_output_format, 1);
+ return 1;
+}
+
+static int diff_tree_sha1_top(const unsigned char *old,
+ const unsigned char *new, const char *base)
+{
+ int ret;
+
+ call_diff_setup();
+ ret = diff_tree_sha1(old, new, base);
+ call_diff_flush();
+ return ret;
+}
+
+static int diff_root_tree(const unsigned char *new, const char *base)
+{
+ int retval;
+ void *tree;
+ unsigned long size;
+
+ call_diff_setup();
+ tree = read_object_with_reference(new, "tree", &size, NULL);
+ if (!tree)
+ die("unable to read root tree (%s)", sha1_to_hex(new));
+ retval = diff_tree("", 0, tree, size, base);
+ free(tree);
+ call_diff_flush();
+ return retval;
+}
+
+static int get_one_line(const char *msg, unsigned long len)
+{
+ int ret = 0;
+
+ while (len--) {
+ ret++;
+ if (*msg++ == '\n')
+ break;
+ }
+ return ret;
+}
+
+static int add_author_info(char *buf, const char *line, int len)
+{
+ char *date;
+ unsigned int namelen;
+ unsigned long time;
+ int tz;
+
+ line += strlen("author ");
+ date = strchr(line, '>');
+ if (!date)
+ return 0;
+ namelen = ++date - line;
+ time = strtoul(date, &date, 10);
+ tz = strtol(date, NULL, 10);
+
+ return sprintf(buf, "Author: %.*s\nDate: %s\n",
+ namelen, line,
+ show_date(time, tz));
+}
+
+static char *generate_header(const char *commit, const char *parent, const char *msg, unsigned long len)
+{
+ static char this_header[16384];
+ int offset;
+
+ offset = sprintf(this_header, "%s%s (from %s)\n", header_prefix, commit, parent);
+ if (verbose_header) {
+ int hdr = 1;
+
+ for (;;) {
+ const char *line = msg;
+ int linelen = get_one_line(msg, len);
+
+ if (!linelen)
+ break;
+
+ /*
+ * We want some slop for indentation and a possible
+ * final "...". Thus the "+ 20".
+ */
+ if (offset + linelen + 20 > sizeof(this_header)) {
+ memcpy(this_header + offset, " ...\n", 8);
+ offset += 8;
+ break;
+ }
+
+ msg += linelen;
+ len -= linelen;
+ if (linelen == 1)
+ hdr = 0;
+ if (hdr) {
+ if (!memcmp(line, "author ", 7))
+ offset += add_author_info(this_header + offset, line, linelen);
+ continue;
+ }
+ memset(this_header + offset, ' ', 4);
+ memcpy(this_header + offset + 4, line, linelen);
+ offset += linelen + 4;
+ }
+ /* Make sure there is an EOLN */
+ if (this_header[offset-1] != '\n')
+ this_header[offset++] = '\n';
+ /* Add _another_ EOLN if we are doing diff output */
+ this_header[offset++] = '\n';
+ this_header[offset] = 0;
+ }
+
+ return this_header;
+}
+
+static int diff_tree_commit(const unsigned char *commit, const char *name)