summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--ui-tree.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/ui-tree.c b/ui-tree.c
index a37a4e5..c6159ec 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -1,246 +1,251 @@
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(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 html("<tr><td class='linenumbers'><pre>"); 25 html("<tr><td class='linenumbers'><pre>");
26 idx = 0; 26 idx = 0;
27 lineno = 0; 27 lineno = 0;
28 htmlf(numberfmt, ++lineno); 28 htmlf(numberfmt, ++lineno);
29 while(idx < size - 1) { // skip absolute last newline 29 while(idx < size - 1) { // skip absolute last newline
30 if (buf[idx] == '\n') 30 if (buf[idx] == '\n')
31 htmlf(numberfmt, ++lineno); 31 htmlf(numberfmt, ++lineno);
32 idx++; 32 idx++;
33 } 33 }
34 html("</pre></td>\n"); 34 html("</pre></td>\n");
35 html("<td class='lines'><pre><code>"); 35 html("<td class='lines'><pre><code>");
36 html_txt(buf); 36 html_txt(buf);
37 html("</code></pre></td></tr></table>\n"); 37 html("</code></pre></td></tr></table>\n");
38} 38}
39 39
40#define ROWLEN 32
41
40static void print_binary_buffer(char *buf, unsigned long size) 42static void print_binary_buffer(char *buf, unsigned long size)
41{ 43{
42 unsigned long ofs, idx; 44 unsigned long ofs, idx;
45 static char ascii[ROWLEN + 1];
43 46
44 html("<table summary='blob content' class='bin-blob'>\n"); 47 html("<table summary='blob content' class='bin-blob'>\n");
45 html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>"); 48 html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>");
46 for (ofs = 0; ofs < size; ofs += 32, buf += 32) { 49 for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) {
47 htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs); 50 htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs);
48 for (idx = 0; idx < 32 && ofs + idx < size; idx++) 51 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
49 htmlf("%*s%02x", 52 htmlf("%*s%02x",
50 idx == 16 ? 4 : 1, "", 53 idx == 16 ? 4 : 1, "",
51 buf[idx] & 0xff); 54 buf[idx] & 0xff);
52 html(" </td><td class='hex'>"); 55 html(" </td><td class='hex'>");
53 for (idx = 0; idx < 32 && ofs + idx < size; idx++) 56 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
54 htmlf("%c", isgraph(buf[idx]) ? buf[idx] : '.'); 57 ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.';
58 ascii[idx] = '\0';
59 html_txt(ascii);
55 html("</td></tr>\n"); 60 html("</td></tr>\n");
56 } 61 }
57 html("</table>\n"); 62 html("</table>\n");
58} 63}
59 64
60static void print_object(const unsigned char *sha1, char *path) 65static void print_object(const unsigned char *sha1, char *path)
61{ 66{
62 enum object_type type; 67 enum object_type type;
63 char *buf; 68 char *buf;
64 unsigned long size; 69 unsigned long size;
65 70
66 type = sha1_object_info(sha1, &size); 71 type = sha1_object_info(sha1, &size);
67 if (type == OBJ_BAD) { 72 if (type == OBJ_BAD) {
68 cgit_print_error(fmt("Bad object name: %s", 73 cgit_print_error(fmt("Bad object name: %s",
69 sha1_to_hex(sha1))); 74 sha1_to_hex(sha1)));
70 return; 75 return;
71 } 76 }
72 77
73 buf = read_sha1_file(sha1, &type, &size); 78 buf = read_sha1_file(sha1, &type, &size);
74 if (!buf) { 79 if (!buf) {
75 cgit_print_error(fmt("Error reading object %s", 80 cgit_print_error(fmt("Error reading object %s",
76 sha1_to_hex(sha1))); 81 sha1_to_hex(sha1)));
77 return; 82 return;
78 } 83 }
79 84
80 html(" ("); 85 html(" (");
81 cgit_plain_link("plain", NULL, NULL, ctx.qry.head, 86 cgit_plain_link("plain", NULL, NULL, ctx.qry.head,
82 curr_rev, path); 87 curr_rev, path);
83 htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1)); 88 htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1));
84 89
85 if (buffer_is_binary(buf, size)) 90 if (buffer_is_binary(buf, size))
86 print_binary_buffer(buf, size); 91 print_binary_buffer(buf, size);
87 else 92 else
88 print_text_buffer(buf, size); 93 print_text_buffer(buf, size);
89} 94}
90 95
91 96
92static int ls_item(const unsigned char *sha1, const char *base, int baselen, 97static int ls_item(const unsigned char *sha1, const char *base, int baselen,
93 const char *pathname, unsigned int mode, int stage, 98 const char *pathname, unsigned int mode, int stage,
94 void *cbdata) 99 void *cbdata)
95{ 100{
96 char *name; 101 char *name;
97 char *fullpath; 102 char *fullpath;
98 enum object_type type; 103 enum object_type type;
99 unsigned long size = 0; 104 unsigned long size = 0;
100 105
101 name = xstrdup(pathname); 106 name = xstrdup(pathname);
102 fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", 107 fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "",
103 ctx.qry.path ? "/" : "", name); 108 ctx.qry.path ? "/" : "", name);
104 109
105 if (!S_ISGITLINK(mode)) { 110 if (!S_ISGITLINK(mode)) {
106 type = sha1_object_info(sha1, &size); 111 type = sha1_object_info(sha1, &size);
107 if (type == OBJ_BAD) { 112 if (type == OBJ_BAD) {
108 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", 113 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>",
109 name, 114 name,
110 sha1_to_hex(sha1)); 115 sha1_to_hex(sha1));
111 return 0; 116 return 0;
112 } 117 }
113 } 118 }
114 119
115 html("<tr><td class='ls-mode'>"); 120 html("<tr><td class='ls-mode'>");
116 cgit_print_filemode(mode); 121 cgit_print_filemode(mode);
117 html("</td><td>"); 122 html("</td><td>");
118 if (S_ISGITLINK(mode)) { 123 if (S_ISGITLINK(mode)) {
119 htmlf("<a class='ls-mod' href='"); 124 htmlf("<a class='ls-mod' href='");
120 html_attr(fmt(ctx.repo->module_link, 125 html_attr(fmt(ctx.repo->module_link,
121 name, 126 name,
122 sha1_to_hex(sha1))); 127 sha1_to_hex(sha1)));
123 html("'>"); 128 html("'>");
124 html_txt(name); 129 html_txt(name);
125 html("</a>"); 130 html("</a>");
126 } else if (S_ISDIR(mode)) { 131 } else if (S_ISDIR(mode)) {
127 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, 132 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head,
128 curr_rev, fullpath); 133 curr_rev, fullpath);
129 } else { 134 } else {
130 cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head, 135 cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head,
131 curr_rev, fullpath); 136 curr_rev, fullpath);
132 } 137 }
133 htmlf("</td><td class='ls-size'>%li</td>", size); 138 htmlf("</td><td class='ls-size'>%li</td>", size);
134 139
135 html("<td>"); 140 html("<td>");
136 cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev, 141 cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev,
137 fullpath, 0, NULL, NULL, ctx.qry.showmsg); 142 fullpath, 0, NULL, NULL, ctx.qry.showmsg);
138 if (ctx.repo->max_stats) 143 if (ctx.repo->max_stats)
139 cgit_stats_link("stats", NULL, "button", ctx.qry.head, 144 cgit_stats_link("stats", NULL, "button", ctx.qry.head,
140 fullpath); 145 fullpath);
141 html("</td></tr>\n"); 146 html("</td></tr>\n");
142 free(name); 147 free(name);
143 return 0; 148 return 0;
144} 149}
145 150
146static void ls_head() 151static void ls_head()
147{ 152{
148 html("<table summary='tree listing' class='list'>\n"); 153 html("<table summary='tree listing' class='list'>\n");
149 html("<tr class='nohover'>"); 154 html("<tr class='nohover'>");
150 html("<th class='left'>Mode</th>"); 155 html("<th class='left'>Mode</th>");
151 html("<th class='left'>Name</th>"); 156 html("<th class='left'>Name</th>");
152 html("<th class='right'>Size</th>"); 157 html("<th class='right'>Size</th>");
153 html("<th/>"); 158 html("<th/>");
154 html("</tr>\n"); 159 html("</tr>\n");
155 header = 1; 160 header = 1;
156} 161}
157 162
158static void ls_tail() 163static void ls_tail()
159{ 164{
160 if (!header) 165 if (!header)
161 return; 166 return;
162 html("</table>\n"); 167 html("</table>\n");
163 header = 0; 168 header = 0;
164} 169}
165 170
166static void ls_tree(const unsigned char *sha1, char *path) 171static void ls_tree(const unsigned char *sha1, char *path)
167{ 172{
168 struct tree *tree; 173 struct tree *tree;
169 174
170 tree = parse_tree_indirect(sha1); 175 tree = parse_tree_indirect(sha1);
171 if (!tree) { 176 if (!tree) {
172 cgit_print_error(fmt("Not a tree object: %s", 177 cgit_print_error(fmt("Not a tree object: %s",
173 sha1_to_hex(sha1))); 178 sha1_to_hex(sha1)));
174 return; 179 return;
175 } 180 }
176 181
177 ls_head(); 182 ls_head();
178 read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL); 183 read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL);
179 ls_tail(); 184 ls_tail();
180} 185}
181 186
182 187
183static int walk_tree(const unsigned char *sha1, const char *base, int baselen, 188static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
184 const char *pathname, unsigned mode, int stage, 189 const char *pathname, unsigned mode, int stage,
185 void *cbdata) 190 void *cbdata)
186{ 191{
187 static int state; 192 static int state;
188 static char buffer[PATH_MAX]; 193 static char buffer[PATH_MAX];
189 char *url; 194 char *url;
190 195
191 if (state == 0) { 196 if (state == 0) {
192 memcpy(buffer, base, baselen); 197 memcpy(buffer, base, baselen);
193 strcpy(buffer+baselen, pathname); 198 strcpy(buffer+baselen, pathname);
194 url = cgit_pageurl(ctx.qry.repo, "tree", 199 url = cgit_pageurl(ctx.qry.repo, "tree",
195 fmt("h=%s&amp;path=%s", curr_rev, buffer)); 200 fmt("h=%s&amp;path=%s", curr_rev, buffer));
196 html("/"); 201 html("/");
197 cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head, 202 cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head,
198 curr_rev, buffer); 203 curr_rev, buffer);
199 204
200 if (strcmp(match_path, buffer)) 205 if (strcmp(match_path, buffer))
201 return READ_TREE_RECURSIVE; 206 return READ_TREE_RECURSIVE;
202 207
203 if (S_ISDIR(mode)) { 208 if (S_ISDIR(mode)) {
204 state = 1; 209 state = 1;
205 ls_head(); 210 ls_head();
206 return READ_TREE_RECURSIVE; 211 return READ_TREE_RECURSIVE;
207 } else { 212 } else {
208 print_object(sha1, buffer); 213 print_object(sha1, buffer);
209 return 0; 214 return 0;
210 } 215 }
211 } 216 }
212 ls_item(sha1, base, baselen, pathname, mode, stage, NULL); 217 ls_item(sha1, base, baselen, pathname, mode, stage, NULL);
213 return 0; 218 return 0;
214} 219}
215 220
216 221
217/* 222/*
218 * Show a tree or a blob 223 * Show a tree or a blob
219 * rev: the commit pointing at the root tree object 224 * rev: the commit pointing at the root tree object
220 * path: path to tree or blob 225 * path: path to tree or blob
221 */ 226 */
222void cgit_print_tree(const char *rev, char *path) 227void cgit_print_tree(const char *rev, char *path)
223{ 228{
224 unsigned char sha1[20]; 229 unsigned char sha1[20];
225 struct commit *commit; 230 struct commit *commit;
226 const char *paths[] = {path, NULL}; 231 const char *paths[] = {path, NULL};
227 232
228 if (!rev) 233 if (!rev)
229 rev = ctx.qry.head; 234 rev = ctx.qry.head;
230 235
231 curr_rev = xstrdup(rev); 236 curr_rev = xstrdup(rev);
232 if (get_sha1(rev, sha1)) { 237 if (get_sha1(rev, sha1)) {
233 cgit_print_error(fmt("Invalid revision name: %s", rev)); 238 cgit_print_error(fmt("Invalid revision name: %s", rev));
234 return; 239 return;
235 } 240 }
236 commit = lookup_commit_reference(sha1); 241 commit = lookup_commit_reference(sha1);
237 if (!commit || parse_commit(commit)) { 242 if (!commit || parse_commit(commit)) {
238 cgit_print_error(fmt("Invalid commit reference: %s", rev)); 243 cgit_print_error(fmt("Invalid commit reference: %s", rev));
239 return; 244 return;
240 } 245 }
241 246
242 html("path: <a href='"); 247 html("path: <a href='");
243 html_attr(cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s", rev))); 248 html_attr(cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s", rev)));
244 html("'>root</a>"); 249 html("'>root</a>");
245 250
246 if (path == NULL) { 251 if (path == NULL) {