summaryrefslogtreecommitdiffabout
path: root/ui-tree.c
Unidiff
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 61fcf5a..c608754 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -1,268 +1,278 @@
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.repo->source_filter) {
26 html("<tr><td class='lines'><pre><code>");
27 ctx.repo->source_filter->argv[1] = xstrdup(name);
28 cgit_open_filter(ctx.repo->source_filter);
29 write(STDOUT_FILENO, buf, size);
30 cgit_close_filter(ctx.repo->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 char *class; 116 char *class;
107 enum object_type type; 117 enum object_type type;
108 unsigned long size = 0; 118 unsigned long size = 0;
109 119
110 name = xstrdup(pathname); 120 name = xstrdup(pathname);
111 fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", 121 fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "",
112 ctx.qry.path ? "/" : "", name); 122 ctx.qry.path ? "/" : "", name);
113 123
114 if (!S_ISGITLINK(mode)) { 124 if (!S_ISGITLINK(mode)) {
115 type = sha1_object_info(sha1, &size); 125 type = sha1_object_info(sha1, &size);
116 if (type == OBJ_BAD) { 126 if (type == OBJ_BAD) {
117 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", 127 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>",
118 name, 128 name,
119 sha1_to_hex(sha1)); 129 sha1_to_hex(sha1));
120 return 0; 130 return 0;
121 } 131 }
122 } 132 }
123 133
124 html("<tr><td class='ls-mode'>"); 134 html("<tr><td class='ls-mode'>");
125 cgit_print_filemode(mode); 135 cgit_print_filemode(mode);
126 html("</td><td>"); 136 html("</td><td>");
127 if (S_ISGITLINK(mode)) { 137 if (S_ISGITLINK(mode)) {
128 htmlf("<a class='ls-mod' href='"); 138 htmlf("<a class='ls-mod' href='");
129 html_attr(fmt(ctx.repo->module_link, 139 html_attr(fmt(ctx.repo->module_link,
130 name, 140 name,
131 sha1_to_hex(sha1))); 141 sha1_to_hex(sha1)));
132 html("'>"); 142 html("'>");
133 html_txt(name); 143 html_txt(name);
134 html("</a>"); 144 html("</a>");
135 } else if (S_ISDIR(mode)) { 145 } else if (S_ISDIR(mode)) {
136 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, 146 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head,
137 curr_rev, fullpath); 147 curr_rev, fullpath);
138 } else { 148 } else {
139 class = strrchr(name, '.'); 149 class = strrchr(name, '.');
140 if (class != NULL) { 150 if (class != NULL) {
141 class = fmt("ls-blob %s", class + 1); 151 class = fmt("ls-blob %s", class + 1);
142 } else 152 } else
143 class = "ls-blob"; 153 class = "ls-blob";
144 cgit_tree_link(name, NULL, class, ctx.qry.head, 154 cgit_tree_link(name, NULL, class, ctx.qry.head,
145 curr_rev, fullpath); 155 curr_rev, fullpath);
146 } 156 }
147 htmlf("</td><td class='ls-size'>%li</td>", size); 157 htmlf("</td><td class='ls-size'>%li</td>", size);
148 158
149 html("<td>"); 159 html("<td>");
150 cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev, 160 cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev,
151 fullpath, 0, NULL, NULL, ctx.qry.showmsg); 161 fullpath, 0, NULL, NULL, ctx.qry.showmsg);
152 if (ctx.repo->max_stats) 162 if (ctx.repo->max_stats)
153 cgit_stats_link("stats", NULL, "button", ctx.qry.head, 163 cgit_stats_link("stats", NULL, "button", ctx.qry.head,
154 fullpath); 164 fullpath);
155 html("</td></tr>\n"); 165 html("</td></tr>\n");
156 free(name); 166 free(name);
157 return 0; 167 return 0;
158} 168}
159 169
160static void ls_head() 170static void ls_head()
161{ 171{
162 html("<table summary='tree listing' class='list'>\n"); 172 html("<table summary='tree listing' class='list'>\n");
163 html("<tr class='nohover'>"); 173 html("<tr class='nohover'>");
164 html("<th class='left'>Mode</th>"); 174 html("<th class='left'>Mode</th>");
165 html("<th class='left'>Name</th>"); 175 html("<th class='left'>Name</th>");
166 html("<th class='right'>Size</th>"); 176 html("<th class='right'>Size</th>");
167 html("<th/>"); 177 html("<th/>");
168 html("</tr>\n"); 178 html("</tr>\n");
169 header = 1; 179 header = 1;
170} 180}
171 181
172static void ls_tail() 182static void ls_tail()
173{ 183{
174 if (!header) 184 if (!header)
175 return; 185 return;
176 html("</table>\n"); 186 html("</table>\n");
177 header = 0; 187 header = 0;
178} 188}
179 189
180static void ls_tree(const unsigned char *sha1, char *path) 190static void ls_tree(const unsigned char *sha1, char *path)
181{ 191{
182 struct tree *tree; 192 struct tree *tree;
183 193
184 tree = parse_tree_indirect(sha1); 194 tree = parse_tree_indirect(sha1);
185 if (!tree) { 195 if (!tree) {
186 cgit_print_error(fmt("Not a tree object: %s", 196 cgit_print_error(fmt("Not a tree object: %s",
187 sha1_to_hex(sha1))); 197 sha1_to_hex(sha1)));
188 return; 198 return;
189 } 199 }
190 200
191 ls_head(); 201 ls_head();
192 read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL); 202 read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL);
193 ls_tail(); 203 ls_tail();
194} 204}
195 205
196 206
197static int walk_tree(const unsigned char *sha1, const char *base, int baselen, 207static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
198 const char *pathname, unsigned mode, int stage, 208 const char *pathname, unsigned mode, int stage,
199 void *cbdata) 209 void *cbdata)
200{ 210{
201 static int state; 211 static int state;
202 static char buffer[PATH_MAX]; 212 static char buffer[PATH_MAX];
203 char *url; 213 char *url;
204 214
205 if (state == 0) { 215 if (state == 0) {
206 memcpy(buffer, base, baselen); 216 memcpy(buffer, base, baselen);
207 strcpy(buffer+baselen, pathname); 217 strcpy(buffer+baselen, pathname);
208 url = cgit_pageurl(ctx.qry.repo, "tree", 218 url = cgit_pageurl(ctx.qry.repo, "tree",
209 fmt("h=%s&amp;path=%s", curr_rev, buffer)); 219 fmt("h=%s&amp;path=%s", curr_rev, buffer));
210 html("/"); 220 html("/");
211 cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head, 221 cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head,
212 curr_rev, buffer); 222 curr_rev, buffer);
213 223
214 if (strcmp(match_path, buffer)) 224 if (strcmp(match_path, buffer))
215 return READ_TREE_RECURSIVE; 225 return READ_TREE_RECURSIVE;
216 226
217 if (S_ISDIR(mode)) { 227 if (S_ISDIR(mode)) {
218 state = 1; 228 state = 1;
219 ls_head(); 229 ls_head();
220 return READ_TREE_RECURSIVE; 230 return READ_TREE_RECURSIVE;
221 } else { 231 } else {
222 print_object(sha1, buffer); 232 print_object(sha1, buffer, pathname);
223 return 0; 233 return 0;
224 } 234 }
225 } 235 }
226 ls_item(sha1, base, baselen, pathname, mode, stage, NULL); 236 ls_item(sha1, base, baselen, pathname, mode, stage, NULL);
227 return 0; 237 return 0;
228} 238}
229 239
230 240
231/* 241/*
232 * Show a tree or a blob 242 * Show a tree or a blob
233 * rev: the commit pointing at the root tree object 243 * rev: the commit pointing at the root tree object
234 * path: path to tree or blob 244 * path: path to tree or blob
235 */ 245 */
236void cgit_print_tree(const char *rev, char *path) 246void cgit_print_tree(const char *rev, char *path)
237{ 247{
238 unsigned char sha1[20]; 248 unsigned char sha1[20];
239 struct commit *commit; 249 struct commit *commit;
240 const char *paths[] = {path, NULL}; 250 const char *paths[] = {path, NULL};
241 251
242 if (!rev) 252 if (!rev)
243 rev = ctx.qry.head; 253 rev = ctx.qry.head;
244 254
245 curr_rev = xstrdup(rev); 255 curr_rev = xstrdup(rev);
246 if (get_sha1(rev, sha1)) { 256 if (get_sha1(rev, sha1)) {
247 cgit_print_error(fmt("Invalid revision name: %s", rev)); 257 cgit_print_error(fmt("Invalid revision name: %s", rev));
248 return; 258 return;
249 } 259 }
250 commit = lookup_commit_reference(sha1); 260 commit = lookup_commit_reference(sha1);
251 if (!commit || parse_commit(commit)) { 261 if (!commit || parse_commit(commit)) {
252 cgit_print_error(fmt("Invalid commit reference: %s", rev)); 262 cgit_print_error(fmt("Invalid commit reference: %s", rev));
253 return; 263 return;
254 } 264 }
255 265
256 html("path: <a href='"); 266 html("path: <a href='");
257 html_attr(cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s", rev))); 267 html_attr(cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s", rev)));
258 html("'>root</a>"); 268 html("'>root</a>");
259 269
260 if (path == NULL) { 270 if (path == NULL) {
261 ls_tree(commit->tree->object.sha1, NULL); 271 ls_tree(commit->tree->object.sha1, NULL);
262 return; 272 return;
263 } 273 }
264 274
265 match_path = path; 275 match_path = path;
266 read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL); 276 read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL);
267 ls_tail(); 277 ls_tail();
268} 278}