summaryrefslogtreecommitdiffabout
path: root/ui-tree.c
authorLars Hjemli <hjemli@gmail.com>2009-07-31 14:55:27 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2009-07-31 15:41:21 (UTC)
commit46b7abed99e957008c01c02cf612aa526ba92f04 (patch) (unidiff)
tree2cdbfe5281c2ffa645def488d53db0a8b82842f4 /ui-tree.c
parent18dfbdc099c1398016427b6fa7f1a1facb363998 (diff)
downloadcgit-46b7abed99e957008c01c02cf612aa526ba92f04.zip
cgit-46b7abed99e957008c01c02cf612aa526ba92f04.tar.gz
cgit-46b7abed99e957008c01c02cf612aa526ba92f04.tar.bz2
ui-tree: add support for source-filter option
This new option is used to specify an external command which will be executed when displaying blob content in the tree view. Blob content will be written to STDIN of the filter and STDOUT from the filter will be included verbatim in the html output from cgit. The file name of the blob will be passed as the only argument to the filter command. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (limited to 'ui-tree.c') (more/less context) (ignore whitespace changes)
-rw-r--r--ui-tree.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/ui-tree.c b/ui-tree.c
index 553dbaa..816e121 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -1,262 +1,272 @@
1/* ui-tree.c: functions for tree output 1/* ui-tree.c: functions for tree output
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include <ctype.h> 9#include <ctype.h>
10#include "cgit.h" 10#include "cgit.h"
11#include "html.h" 11#include "html.h"
12#include "ui-shared.h" 12#include "ui-shared.h"
13 13
14char *curr_rev; 14char *curr_rev;
15char *match_path; 15char *match_path;
16int header = 0; 16int header = 0;
17 17
18static void print_text_buffer(char *buf, unsigned long size) 18static void print_text_buffer(const char *name, char *buf, unsigned long size)
19{ 19{
20 unsigned long lineno, idx; 20 unsigned long lineno, idx;
21 const char *numberfmt = 21 const char *numberfmt =
22 "<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n"; 22 "<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n";
23 23
24 html("<table summary='blob content' class='blob'>\n"); 24 html("<table summary='blob content' class='blob'>\n");
25 if (ctx.cfg.source_filter) {
26 html("<tr><td class='lines'><pre><code>");
27 ctx.cfg.source_filter->argv[1] = xstrdup(name);
28 cgit_open_filter(ctx.cfg.source_filter);
29 write(STDOUT_FILENO, buf, size);
30 cgit_close_filter(ctx.cfg.source_filter);
31 html("</code></pre></td></tr></table>\n");
32 return;
33 }
34
25 html("<tr><td class='linenumbers'><pre>"); 35 html("<tr><td class='linenumbers'><pre>");
26 idx = 0; 36 idx = 0;
27 lineno = 0; 37 lineno = 0;
28 38
29 if (size) { 39 if (size) {
30 htmlf(numberfmt, ++lineno); 40 htmlf(numberfmt, ++lineno);
31 while(idx < size - 1) { // skip absolute last newline 41 while(idx < size - 1) { // skip absolute last newline
32 if (buf[idx] == '\n') 42 if (buf[idx] == '\n')
33 htmlf(numberfmt, ++lineno); 43 htmlf(numberfmt, ++lineno);
34 idx++; 44 idx++;
35 } 45 }
36 } 46 }
37 html("</pre></td>\n"); 47 html("</pre></td>\n");
38 html("<td class='lines'><pre><code>"); 48 html("<td class='lines'><pre><code>");
39 html_txt(buf); 49 html_txt(buf);
40 html("</code></pre></td></tr></table>\n"); 50 html("</code></pre></td></tr></table>\n");
41} 51}
42 52
43#define ROWLEN 32 53#define ROWLEN 32
44 54
45static void print_binary_buffer(char *buf, unsigned long size) 55static void print_binary_buffer(char *buf, unsigned long size)
46{ 56{
47 unsigned long ofs, idx; 57 unsigned long ofs, idx;
48 static char ascii[ROWLEN + 1]; 58 static char ascii[ROWLEN + 1];
49 59
50 html("<table summary='blob content' class='bin-blob'>\n"); 60 html("<table summary='blob content' class='bin-blob'>\n");
51 html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>"); 61 html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>");
52 for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) { 62 for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) {
53 htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs); 63 htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs);
54 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) 64 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
55 htmlf("%*s%02x", 65 htmlf("%*s%02x",
56 idx == 16 ? 4 : 1, "", 66 idx == 16 ? 4 : 1, "",
57 buf[idx] & 0xff); 67 buf[idx] & 0xff);
58 html(" </td><td class='hex'>"); 68 html(" </td><td class='hex'>");
59 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) 69 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
60 ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.'; 70 ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.';
61 ascii[idx] = '\0'; 71 ascii[idx] = '\0';
62 html_txt(ascii); 72 html_txt(ascii);
63 html("</td></tr>\n"); 73 html("</td></tr>\n");
64 } 74 }
65 html("</table>\n"); 75 html("</table>\n");
66} 76}
67 77
68static void print_object(const unsigned char *sha1, char *path) 78static void print_object(const unsigned char *sha1, char *path, const char *basename)
69{ 79{
70 enum object_type type; 80 enum object_type type;
71 char *buf; 81 char *buf;
72 unsigned long size; 82 unsigned long size;
73 83
74 type = sha1_object_info(sha1, &size); 84 type = sha1_object_info(sha1, &size);
75 if (type == OBJ_BAD) { 85 if (type == OBJ_BAD) {
76 cgit_print_error(fmt("Bad object name: %s", 86 cgit_print_error(fmt("Bad object name: %s",
77 sha1_to_hex(sha1))); 87 sha1_to_hex(sha1)));
78 return; 88 return;
79 } 89 }
80 90
81 buf = read_sha1_file(sha1, &type, &size); 91 buf = read_sha1_file(sha1, &type, &size);
82 if (!buf) { 92 if (!buf) {
83 cgit_print_error(fmt("Error reading object %s", 93 cgit_print_error(fmt("Error reading object %s",
84 sha1_to_hex(sha1))); 94 sha1_to_hex(sha1)));
85 return; 95 return;
86 } 96 }
87 97
88 html(" ("); 98 html(" (");
89 cgit_plain_link("plain", NULL, NULL, ctx.qry.head, 99 cgit_plain_link("plain", NULL, NULL, ctx.qry.head,
90 curr_rev, path); 100 curr_rev, path);
91 htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1)); 101 htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1));
92 102
93 if (buffer_is_binary(buf, size)) 103 if (buffer_is_binary(buf, size))
94 print_binary_buffer(buf, size); 104 print_binary_buffer(buf, size);
95 else 105 else
96 print_text_buffer(buf, size); 106 print_text_buffer(basename, buf, size);
97} 107}
98 108
99 109
100static int ls_item(const unsigned char *sha1, const char *base, int baselen, 110static int ls_item(const unsigned char *sha1, const char *base, int baselen,
101 const char *pathname, unsigned int mode, int stage, 111 const char *pathname, unsigned int mode, int stage,
102 void *cbdata) 112 void *cbdata)
103{ 113{
104 char *name; 114 char *name;
105 char *fullpath; 115 char *fullpath;
106 enum object_type type; 116 enum object_type type;
107 unsigned long size = 0; 117 unsigned long size = 0;
108 118
109 name = xstrdup(pathname); 119 name = xstrdup(pathname);
110 fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", 120 fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "",
111 ctx.qry.path ? "/" : "", name); 121 ctx.qry.path ? "/" : "", name);
112 122
113 if (!S_ISGITLINK(mode)) { 123 if (!S_ISGITLINK(mode)) {
114 type = sha1_object_info(sha1, &size); 124 type = sha1_object_info(sha1, &size);
115 if (type == OBJ_BAD) { 125 if (type == OBJ_BAD) {
116 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", 126 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>",
117 name, 127 name,
118 sha1_to_hex(sha1)); 128 sha1_to_hex(sha1));
119 return 0; 129 return 0;
120 } 130 }
121 } 131 }
122 132
123 html("<tr><td class='ls-mode'>"); 133 html("<tr><td class='ls-mode'>");
124 cgit_print_filemode(mode); 134 cgit_print_filemode(mode);
125 html("</td><td>"); 135 html("</td><td>");
126 if (S_ISGITLINK(mode)) { 136 if (S_ISGITLINK(mode)) {
127 htmlf("<a class='ls-mod' href='"); 137 htmlf("<a class='ls-mod' href='");
128 html_attr(fmt(ctx.repo->module_link, 138 html_attr(fmt(ctx.repo->module_link,
129 name, 139 name,
130 sha1_to_hex(sha1))); 140 sha1_to_hex(sha1)));
131 html("'>"); 141 html("'>");
132 html_txt(name); 142 html_txt(name);
133 html("</a>"); 143 html("</a>");
134 } else if (S_ISDIR(mode)) { 144 } else if (S_ISDIR(mode)) {
135 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, 145 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head,
136 curr_rev, fullpath); 146 curr_rev, fullpath);
137 } else { 147 } else {
138 cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head, 148 cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head,
139 curr_rev, fullpath); 149 curr_rev, fullpath);
140 } 150 }
141 htmlf("</td><td class='ls-size'>%li</td>", size); 151 htmlf("</td><td class='ls-size'>%li</td>", size);
142 152
143 html("<td>"); 153 html("<td>");
144 cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev, 154 cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev,
145 fullpath, 0, NULL, NULL, ctx.qry.showmsg); 155 fullpath, 0, NULL, NULL, ctx.qry.showmsg);
146 if (ctx.repo->max_stats) 156 if (ctx.repo->max_stats)
147 cgit_stats_link("stats", NULL, "button", ctx.qry.head, 157 cgit_stats_link("stats", NULL, "button", ctx.qry.head,
148 fullpath); 158 fullpath);
149 html("</td></tr>\n"); 159 html("</td></tr>\n");
150 free(name); 160 free(name);
151 return 0; 161 return 0;
152} 162}
153 163
154static void ls_head() 164static void ls_head()
155{ 165{
156 html("<table summary='tree listing' class='list'>\n"); 166 html("<table summary='tree listing' class='list'>\n");
157 html("<tr class='nohover'>"); 167 html("<tr class='nohover'>");
158 html("<th class='left'>Mode</th>"); 168 html("<th class='left'>Mode</th>");
159 html("<th class='left'>Name</th>"); 169 html("<th class='left'>Name</th>");
160 html("<th class='right'>Size</th>"); 170 html("<th class='right'>Size</th>");
161 html("<th/>"); 171 html("<th/>");
162 html("</tr>\n"); 172 html("</tr>\n");
163 header = 1; 173 header = 1;
164} 174}
165 175
166static void ls_tail() 176static void ls_tail()
167{ 177{
168 if (!header) 178 if (!header)
169 return; 179 return;
170 html("</table>\n"); 180 html("</table>\n");
171 header = 0; 181 header = 0;
172} 182}
173 183
174static void ls_tree(const unsigned char *sha1, char *path) 184static void ls_tree(const unsigned char *sha1, char *path)
175{ 185{
176 struct tree *tree; 186 struct tree *tree;
177 187
178 tree = parse_tree_indirect(sha1); 188 tree = parse_tree_indirect(sha1);
179 if (!tree) { 189 if (!tree) {
180 cgit_print_error(fmt("Not a tree object: %s", 190 cgit_print_error(fmt("Not a tree object: %s",
181 sha1_to_hex(sha1))); 191 sha1_to_hex(sha1)));
182 return; 192 return;
183 } 193 }
184 194
185 ls_head(); 195 ls_head();
186 read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL); 196 read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL);
187 ls_tail(); 197 ls_tail();
188} 198}
189 199
190 200
191static int walk_tree(const unsigned char *sha1, const char *base, int baselen, 201static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
192 const char *pathname, unsigned mode, int stage, 202 const char *pathname, unsigned mode, int stage,
193 void *cbdata) 203 void *cbdata)
194{ 204{
195 static int state; 205 static int state;
196 static char buffer[PATH_MAX]; 206 static char buffer[PATH_MAX];
197 char *url; 207 char *url;
198 208
199 if (state == 0) { 209 if (state == 0) {
200 memcpy(buffer, base, baselen); 210 memcpy(buffer, base, baselen);
201 strcpy(buffer+baselen, pathname); 211 strcpy(buffer+baselen, pathname);
202 url = cgit_pageurl(ctx.qry.repo, "tree", 212 url = cgit_pageurl(ctx.qry.repo, "tree",
203 fmt("h=%s&amp;path=%s", curr_rev, buffer)); 213 fmt("h=%s&amp;path=%s", curr_rev, buffer));
204 html("/"); 214 html("/");
205 cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head, 215 cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head,
206 curr_rev, buffer); 216 curr_rev, buffer);
207 217
208 if (strcmp(match_path, buffer)) 218 if (strcmp(match_path, buffer))
209 return READ_TREE_RECURSIVE; 219 return READ_TREE_RECURSIVE;
210 220
211 if (S_ISDIR(mode)) { 221 if (S_ISDIR(mode)) {
212 state = 1; 222 state = 1;
213 ls_head(); 223 ls_head();
214 return READ_TREE_RECURSIVE; 224 return READ_TREE_RECURSIVE;
215 } else { 225 } else {
216 print_object(sha1, buffer); 226 print_object(sha1, buffer, pathname);
217 return 0; 227 return 0;
218 } 228 }
219 } 229 }
220 ls_item(sha1, base, baselen, pathname, mode, stage, NULL); 230 ls_item(sha1, base, baselen, pathname, mode, stage, NULL);
221 return 0; 231 return 0;
222} 232}
223 233
224 234
225/* 235/*
226 * Show a tree or a blob 236 * Show a tree or a blob
227 * rev: the commit pointing at the root tree object 237 * rev: the commit pointing at the root tree object
228 * path: path to tree or blob 238 * path: path to tree or blob
229 */ 239 */
230void cgit_print_tree(const char *rev, char *path) 240void cgit_print_tree(const char *rev, char *path)
231{ 241{
232 unsigned char sha1[20]; 242 unsigned char sha1[20];
233 struct commit *commit; 243 struct commit *commit;
234 const char *paths[] = {path, NULL}; 244 const char *paths[] = {path, NULL};
235 245
236 if (!rev) 246 if (!rev)
237 rev = ctx.qry.head; 247 rev = ctx.qry.head;
238 248
239 curr_rev = xstrdup(rev); 249 curr_rev = xstrdup(rev);
240 if (get_sha1(rev, sha1)) { 250 if (get_sha1(rev, sha1)) {
241 cgit_print_error(fmt("Invalid revision name: %s", rev)); 251 cgit_print_error(fmt("Invalid revision name: %s", rev));
242 return; 252 return;
243 } 253 }
244 commit = lookup_commit_reference(sha1); 254 commit = lookup_commit_reference(sha1);
245 if (!commit || parse_commit(commit)) { 255 if (!commit || parse_commit(commit)) {
246 cgit_print_error(fmt("Invalid commit reference: %s", rev)); 256 cgit_print_error(fmt("Invalid commit reference: %s", rev));
247 return; 257 return;
248 } 258 }
249 259
250 html("path: <a href='"); 260 html("path: <a href='");
251 html_attr(cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s", rev))); 261 html_attr(cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s", rev)));
252 html("'>root</a>"); 262 html("'>root</a>");
253 263
254 if (path == NULL) { 264 if (path == NULL) {
255 ls_tree(commit->tree->object.sha1, NULL); 265 ls_tree(commit->tree->object.sha1, NULL);
256 return; 266 return;
257 } 267 }
258 268
259 match_path = path; 269 match_path = path;
260 read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL); 270 read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL);
261 ls_tail(); 271 ls_tail();
262} 272}