all repos — cgit @ 27cd3b2a700e1cc46cd0393ddea48c07b62ee3a6

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#include "xdiff.h"
 11
 12char *diff_buffer;
 13int diff_buffer_size;
 14
 15
 16/*
 17 * print a single line returned from xdiff
 18 */
 19static void print_line(char *line, int len)
 20{
 21	char *class = "ctx";
 22	char c = line[len-1];
 23
 24	if (line[0] == '+')
 25		class = "add";
 26	else if (line[0] == '-')
 27		class = "del";
 28	else if (line[0] == '@')
 29		class = "hunk";
 30
 31	htmlf("<div class='%s'>", class);
 32	line[len-1] = '\0';
 33	html_txt(line);
 34	html("</div>");
 35	line[len-1] = c;
 36}
 37
 38/*
 39 * Receive diff-buffers from xdiff and concatenate them as
 40 * needed across multiple callbacks.
 41 *
 42 * This is basically a copy of xdiff-interface.c/xdiff_outf(),
 43 * ripped from git and modified to use globals instead of
 44 * a special callback-struct.
 45 */
 46int diff_cb(void *priv_, mmbuffer_t *mb, int nbuf)
 47{
 48	int i;
 49
 50	for (i = 0; i < nbuf; i++) {
 51		if (mb[i].ptr[mb[i].size-1] != '\n') {
 52			/* Incomplete line */
 53			diff_buffer = xrealloc(diff_buffer,
 54					       diff_buffer_size + mb[i].size);
 55			memcpy(diff_buffer + diff_buffer_size,
 56			       mb[i].ptr, mb[i].size);
 57			diff_buffer_size += mb[i].size;
 58			continue;
 59		}
 60
 61		/* we have a complete line */
 62		if (!diff_buffer) {
 63			print_line(mb[i].ptr, mb[i].size);
 64			continue;
 65		}
 66		diff_buffer = xrealloc(diff_buffer,
 67				       diff_buffer_size + mb[i].size);
 68		memcpy(diff_buffer + diff_buffer_size, mb[i].ptr, mb[i].size);
 69		print_line(diff_buffer, diff_buffer_size + mb[i].size);
 70		free(diff_buffer);
 71		diff_buffer = NULL;
 72		diff_buffer_size = 0;
 73	}
 74	if (diff_buffer) {
 75		print_line(diff_buffer, diff_buffer_size);
 76		free(diff_buffer);
 77		diff_buffer = NULL;
 78		diff_buffer_size = 0;
 79	}
 80	return 0;
 81}
 82
 83static int load_mmfile(mmfile_t *file, const unsigned char *sha1)
 84{
 85	char type[20];
 86
 87	if (is_null_sha1(sha1)) {
 88		file->ptr = (char *)"";
 89		file->size = 0;
 90	} else {
 91		file->ptr = read_sha1_file(sha1, type, &file->size);
 92	}
 93	return 1;
 94}
 95
 96static void run_diff(const unsigned char *sha1, const unsigned char *sha2)
 97{
 98	mmfile_t file1, file2;
 99	xpparam_t diff_params;
100	xdemitconf_t emit_params;
101	xdemitcb_t emit_cb;
102
103	if (!load_mmfile(&file1, sha1) || !load_mmfile(&file2, sha2)) {
104		cgit_print_error("Unable to load files for diff");
105		return;
106	}
107
108	diff_params.flags = XDF_NEED_MINIMAL;
109
110	emit_params.ctxlen = 3;
111	emit_params.flags = XDL_EMIT_FUNCNAMES;
112
113	emit_cb.outf = diff_cb;
114
115	xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb);
116}
117
118
119
120void cgit_print_diff(const char *old_hex, const char *new_hex)
121{
122	unsigned char sha1[20], sha2[20];
123
124	get_sha1(old_hex, sha1);
125	get_sha1(new_hex, sha2);
126
127	html("<h2>diff</h2>\n");
128	html("<table class='diff'><tr><td>");
129	run_diff(sha1, sha2);
130	html("</td></tr></table>");
131}