]> gitweb.ps.run Git - ps-cgit/blob - ui-diff.c
Add shared diff-handling functions
[ps-cgit] / ui-diff.c
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 char *diff_buffer;
12 int diff_buffer_size;
13
14
15 /*
16  * print a single line returned from xdiff
17  */
18 static 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  */
45 int 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
82 static 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
95 static 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
119 void 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 }