all repos — cgit @ 0c8e184e9cbf4d3a1e907de9125f6d8210c169d6

a hyperfast web frontend for git written in c

ui-diff.c (view raw)

  1/* ui-diff.c: show diff between two blobs
  2 *
  3 * Copyright (C) 2006 Lars Hjemli
  4 *
  5 * Licensed under GNU General Public License v2
  6 *   (see COPYING for full license text)
  7 */
  8
  9#include "cgit.h"
 10
 11
 12unsigned char old_rev_sha1[20];
 13unsigned char new_rev_sha1[20];
 14
 15/*
 16 * print a single line returned from xdiff
 17 */
 18static void print_line(char *line, int len)
 19{
 20	char *class = "ctx";
 21	char c = line[len-1];
 22
 23	if (line[0] == '+')
 24		class = "add";
 25	else if (line[0] == '-')
 26		class = "del";
 27	else if (line[0] == '@')
 28		class = "hunk";
 29
 30	htmlf("<div class='%s'>", class);
 31	line[len-1] = '\0';
 32	html_txt(line);
 33	html("</div>");
 34	line[len-1] = c;
 35}
 36
 37static void header(unsigned char *sha1, char *path1, int mode1,
 38		   unsigned char *sha2, char *path2, int mode2)
 39{
 40	char *abbrev1, *abbrev2;
 41	int subproject;
 42
 43	subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2));
 44	html("<div class='head'>");
 45	html("diff --git a/");
 46	html_txt(path1);
 47	html(" b/");
 48	html_txt(path2);
 49
 50	if (is_null_sha1(sha1))
 51		path1 = "dev/null";
 52	if (is_null_sha1(sha2))
 53		path2 = "dev/null";
 54
 55	if (mode1 == 0)
 56		htmlf("<br/>new file mode %.6o", mode2);
 57
 58	if (mode2 == 0)
 59		htmlf("<br/>deleted file mode %.6o", mode1);
 60
 61	if (!subproject) {
 62		abbrev1 = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));
 63		abbrev2 = xstrdup(find_unique_abbrev(sha2, DEFAULT_ABBREV));
 64		htmlf("<br/>index %s..%s", abbrev1, abbrev2);
 65		free(abbrev1);
 66		free(abbrev2);
 67		if (mode1 != 0 && mode2 != 0) {
 68			htmlf(" %.6o", mode1);
 69			if (mode2 != mode1)
 70				htmlf("..%.6o", mode2);
 71		}
 72		html("<br/>--- a/");
 73		if (mode1 != 0)
 74			cgit_tree_link(path1, NULL, NULL, cgit_query_head,
 75				       sha1_to_hex(old_rev_sha1), path1);
 76		else
 77			html_txt(path1);
 78		html("<br/>+++ b/");
 79		if (mode2 != 0)
 80			cgit_tree_link(path2, NULL, NULL, cgit_query_head,
 81				       sha1_to_hex(new_rev_sha1), path2);
 82		else
 83			html_txt(path2);
 84	}
 85	html("</div>");
 86}
 87
 88static void filepair_cb(struct diff_filepair *pair)
 89{
 90	header(pair->one->sha1, pair->one->path, pair->one->mode,
 91	       pair->two->sha1, pair->two->path, pair->two->mode);
 92	if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) {
 93		if (S_ISGITLINK(pair->one->mode))
 94			print_line(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52);
 95		if (S_ISGITLINK(pair->two->mode))
 96			print_line(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52);
 97		return;
 98	}
 99	if (cgit_diff_files(pair->one->sha1, pair->two->sha1, print_line))
100		cgit_print_error("Error running diff");
101}
102
103void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefix)
104{
105	enum object_type type;
106	unsigned long size;
107	struct commit *commit, *commit2;
108
109	if (!new_rev)
110		new_rev = cgit_query_head;
111	get_sha1(new_rev, new_rev_sha1);
112	type = sha1_object_info(new_rev_sha1, &size);
113	if (type == OBJ_BAD) {
114		cgit_print_error(fmt("Bad object name: %s", new_rev));
115		return;
116	}
117	if (type != OBJ_COMMIT) {
118		cgit_print_error(fmt("Unhandled object type: %s",
119				     typename(type)));
120		return;
121	}
122
123	commit = lookup_commit_reference(new_rev_sha1);
124	if (!commit || parse_commit(commit))
125		cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(new_rev_sha1)));
126
127	if (old_rev)
128		get_sha1(old_rev, old_rev_sha1);
129	else if (commit->parents && commit->parents->item)
130		hashcpy(old_rev_sha1, commit->parents->item->object.sha1);
131	else
132		hashclr(old_rev_sha1);
133
134	if (!is_null_sha1(old_rev_sha1)) {
135		type = sha1_object_info(old_rev_sha1, &size);
136		if (type == OBJ_BAD) {
137			cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(old_rev_sha1)));
138			return;
139		}
140		commit2 = lookup_commit_reference(old_rev_sha1);
141		if (!commit2 || parse_commit(commit2))
142			cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(old_rev_sha1)));
143	}
144	html("<table class='diff'>");
145	html("<tr><td>");
146	cgit_diff_tree(old_rev_sha1, new_rev_sha1, filepair_cb, prefix);
147	html("</td></tr>");
148	html("</table>");
149}