all repos — cgit @ 40e174d5364910750413d94b5417e57d108190ef

a hyperfast web frontend for git written in c

ui-ssdiff.c (view raw)

  1#include "cgit.h"
  2#include "html.h"
  3#include "ui-shared.h"
  4
  5extern int use_ssdiff;
  6
  7static int current_old_line, current_new_line;
  8
  9struct deferred_lines {
 10	int line_no;
 11	char *line;
 12	struct deferred_lines *next;
 13};
 14
 15static struct deferred_lines *deferred_old, *deferred_old_last;
 16static struct deferred_lines *deferred_new, *deferred_new_last;
 17
 18static int line_from_hunk(char *line, char type)
 19{
 20	char *buf1, *buf2;
 21	int len;
 22
 23	buf1 = strchr(line, type);
 24	if (buf1 == NULL)
 25		return 0;
 26	buf1 += 1;
 27	buf2 = strchr(buf1, ',');
 28	if (buf2 == NULL)
 29		return 0;
 30	len = buf2 - buf1;
 31	buf2 = xmalloc(len + 1);
 32	strncpy(buf2, buf1, len);
 33	buf2[len] = '\0';
 34	int res = atoi(buf2);
 35	free(buf2);
 36	return res;
 37}
 38
 39static char *replace_tabs(char *line)
 40{
 41	char *prev_buf = line;
 42	char *cur_buf;
 43        int linelen = strlen(line);
 44	int n_tabs = 0;
 45        int i;
 46	char *result;
 47	char *spaces = "        ";
 48
 49	if (linelen == 0) {
 50		result = xmalloc(1);
 51		result[0] = '\0';
 52		return result;
 53	}
 54
 55        for (i = 0; i < linelen; i++)
 56		if (line[i] == '\t')
 57			n_tabs += 1;
 58        result = xmalloc(linelen + n_tabs * 8 + 1);
 59	result[0] = '\0';
 60
 61	while (1) {
 62		cur_buf = strchr(prev_buf, '\t');
 63		if (!cur_buf) {
 64			strcat(result, prev_buf);
 65			break;
 66		} else {
 67			strcat(result, " ");
 68			strncat(result, spaces, 8 - (strlen(result) % 8));
 69			strncat(result, prev_buf, cur_buf - prev_buf);
 70		}
 71		prev_buf = cur_buf + 1;
 72	}
 73	return result;
 74}
 75
 76static void deferred_old_add(char *line, int line_no)
 77{
 78	struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines));
 79	item->line = xstrdup(line);
 80	item->line_no = line_no;
 81	item->next = NULL;
 82	if (deferred_old) {
 83		deferred_old_last->next = item;
 84		deferred_old_last = item;
 85	} else {
 86		deferred_old = deferred_old_last = item;
 87	}
 88}
 89
 90static void deferred_new_add(char *line, int line_no)
 91{
 92	struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines));
 93	item->line = xstrdup(line);
 94	item->line_no = line_no;
 95	item->next = NULL;
 96	if (deferred_new) {
 97		deferred_new_last->next = item;
 98		deferred_new_last = item;
 99	} else {
100		deferred_new = deferred_new_last = item;
101	}
102}
103
104static void print_ssdiff_line(char *class, int old_line_no, char *old_line,
105			      int new_line_no, char *new_line)
106{
107	html("<tr>");
108	if (old_line_no > 0)
109		htmlf("<td class='%s'>%d </td><td class='%s'>", class,
110		      old_line_no, class);
111	else
112		htmlf("<td class='%s_dark'>  </td><td class='%s_dark'>", class, class);
113
114	if (old_line) {
115		old_line = replace_tabs(old_line + 1);
116		html_txt(old_line);
117		free(old_line);
118	}
119
120	html("  </td>");
121
122	if (new_line_no > 0)
123		htmlf("<td class='%s'>  %d </td><td class='%s'>", class,
124		      new_line_no, class);
125	else
126		htmlf("<td class='%s_dark'>  </td><td class='%s_dark'>", class, class);
127
128	if (new_line) {
129		new_line = replace_tabs(new_line + 1);
130		html_txt(new_line);
131		free(new_line);
132	}
133
134	html("</td></tr>");
135}
136
137static void print_deferred_old_lines()
138{
139	struct deferred_lines *iter_old, *tmp;
140
141	iter_old = deferred_old;
142	while (iter_old) {
143		print_ssdiff_line("del", iter_old->line_no,
144				  iter_old->line, -1, NULL);
145		tmp = iter_old->next;
146		free(iter_old);
147		iter_old = tmp;
148	}
149}
150
151static void print_deferred_new_lines()
152{
153	struct deferred_lines *iter_new, *tmp;
154
155	iter_new = deferred_new;
156	while (iter_new) {
157		print_ssdiff_line("add", -1, NULL, iter_new->line_no,
158				  iter_new->line);
159		tmp = iter_new->next;
160		free(iter_new);
161		iter_new = tmp;
162	}
163}
164
165static void print_deferred_changed_lines()
166{
167	struct deferred_lines *iter_old, *iter_new, *tmp;
168
169	iter_old = deferred_old;
170	iter_new = deferred_new;
171	while (iter_old || iter_new) {
172		if (iter_old && iter_new)
173			print_ssdiff_line("changed", iter_old->line_no,
174					  iter_old->line,
175					  iter_new->line_no, iter_new->line);
176		else if (iter_old)
177			print_ssdiff_line("changed", iter_old->line_no,
178					  iter_old->line, -1, NULL);
179		else if (iter_new)
180			print_ssdiff_line("changed", -1, NULL,
181					  iter_new->line_no, iter_new->line);
182
183		if (iter_old) {
184			tmp = iter_old->next;
185			free(iter_old);
186			iter_old = tmp;
187		}
188
189		if (iter_new) {
190			tmp = iter_new->next;
191			free(iter_new);
192			iter_new = tmp;
193		}
194	}
195}
196
197void cgit_ssdiff_print_deferred_lines()
198{
199	if (!deferred_old && !deferred_new)
200		return;
201
202	if (deferred_old && !deferred_new)
203		print_deferred_old_lines();
204	else if (!deferred_old && deferred_new)
205		print_deferred_new_lines();
206	else
207		print_deferred_changed_lines();
208
209	deferred_old = deferred_old_last = NULL;
210	deferred_new = deferred_new_last = NULL;
211}
212
213/*
214 * print a single line returned from xdiff
215 */
216void cgit_ssdiff_line_cb(char *line, int len)
217{
218	char c = line[len - 1];
219
220	line[len - 1] = '\0';
221
222	if (line[0] == '@') {
223		current_old_line = line_from_hunk(line, '-');
224		current_new_line = line_from_hunk(line, '+');
225	}
226
227	if (line[0] == ' ') {
228		if (deferred_old || deferred_new)
229			cgit_ssdiff_print_deferred_lines();
230		print_ssdiff_line("ctx", current_old_line, line,
231				  current_new_line, line);
232		current_old_line += 1;
233		current_new_line += 1;
234	} else if (line[0] == '+') {
235		deferred_new_add(line, current_new_line);
236		current_new_line += 1;
237	} else if (line[0] == '-') {
238		deferred_old_add(line, current_old_line);
239		current_old_line += 1;
240	} else if (line[0] == '@') {
241		html("<tr><td colspan='4' class='hunk'>");
242		html_txt(line);
243		html("</td></tr>");
244	} else {
245		html("<tr><td colspan='4' class='ctx'>");
246		html_txt(line);
247		html("</td></tr>");
248	}
249	line[len - 1] = c;
250}
251
252void cgit_ssdiff_header()
253{
254	current_old_line = 0;
255	current_new_line = 0;
256	html("<table class='ssdiff'>");
257}
258
259void cgit_ssdiff_footer()
260{
261	if (deferred_old || deferred_new)
262		cgit_ssdiff_print_deferred_lines();
263	html("</table>");
264}