all repos — cgit @ ca8eb8fc8f71ee0a40015c323619f776840b6503

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