summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.css14
-rw-r--r--cgit.h1
-rw-r--r--cgitrc1
-rw-r--r--shared.c8
-rw-r--r--ui-summary.c14
5 files changed, 23 insertions, 15 deletions
diff --git a/cgit.css b/cgit.css
index 327eaba..8977533 100644
--- a/cgit.css
+++ b/cgit.css
@@ -1,414 +1,412 @@
1body { 1body {
2 font-family: arial; 2 font-family: arial;
3 font-size: 11pt; 3 font-size: 11pt;
4 background: white; 4 background: white;
5} 5}
6 6
7body, table { 7body, table {
8 padding: 0em; 8 padding: 0em;
9 margin: 0em; 9 margin: 0em;
10} 10}
11 11
12table { 12table {
13 border-collapse: collapse; 13 border-collapse: collapse;
14} 14}
15 15
16h2 { 16h2 {
17 font-size: 120%; 17 font-size: 120%;
18 font-weight: bold; 18 font-weight: bold;
19 margin-top: 0em; 19 margin-top: 0em;
20 margin-bottom: 0.25em; 20 margin-bottom: 0.25em;
21} 21}
22 22
23h3 { 23h3 {
24 margin-top: 0em; 24 margin-top: 0em;
25 font-size: 100%; 25 font-size: 100%;
26 font-weight: normal; 26 font-weight: normal;
27} 27}
28 28
29h4 { 29h4 {
30 margin-top: 1.5em; 30 margin-top: 1.5em;
31 margin-bottom: 0.1em; 31 margin-bottom: 0.1em;
32 font-size: 100%; 32 font-size: 100%;
33 font-weight: bold; 33 font-weight: bold;
34} 34}
35 35
36a { 36a {
37 color: blue; 37 color: blue;
38 text-decoration: none; 38 text-decoration: none;
39} 39}
40 40
41a:hover { 41a:hover {
42 text-decoration: underline; 42 text-decoration: underline;
43} 43}
44 44
45table.list { 45table.list {
46 border: none; 46 border: none;
47 border-collapse: collapse; 47 border-collapse: collapse;
48} 48}
49 49
50table.list tr { 50table.list tr {
51 background: white; 51 background: white;
52} 52}
53 53
54table.list tr:hover { 54table.list tr:hover {
55 background: #eee; 55 background: #eee;
56} 56}
57 57
58table.list tr.nohover:hover { 58table.list tr.nohover:hover {
59 background: white; 59 background: white;
60} 60}
61 61
62table.list th { 62table.list th {
63 font-weight: bold; 63 font-weight: bold;
64 border-bottom: solid 1px #777; 64 border-bottom: solid 1px #777;
65 padding: 0.1em 0.5em 0.1em 0.5em; 65 padding: 0.1em 0.5em 0.1em 0.5em;
66 vertical-align: baseline; 66 vertical-align: baseline;
67} 67}
68 68
69table.list td { 69table.list td {
70 border: none; 70 border: none;
71 padding: 0.1em 0.5em 0.1em 0.5em; 71 padding: 0.1em 0.5em 0.1em 0.5em;
72} 72}
73 73
74img { 74img {
75 border: none; 75 border: none;
76} 76}
77 77
78table#layout { 78table#layout {
79 width: 100%; 79 width: 100%;
80 border-collapse: collapse; 80 border-collapse: collapse;
81 margin: 0px; 81 margin: 0px;
82} 82}
83 83
84td#header, td#logo { 84td#header, td#logo {
85 color: #666; 85 color: #666;
86 background-color: #ddd; 86 background-color: #ddd;
87 border-bottom: solid 1px #000; 87 border-bottom: solid 1px #000;
88} 88}
89 89
90td#header { 90td#header {
91 font-size: 150%; 91 font-size: 150%;
92 font-weight: bold; 92 font-weight: bold;
93 padding: 0.2em 0.5em; 93 padding: 0.2em 0.5em;
94 vertical-align: text-bottom; 94 vertical-align: text-bottom;
95} 95}
96 96
97td#logo { 97td#logo {
98 text-align: right; 98 text-align: right;
99 vertical-align: middle; 99 vertical-align: middle;
100 padding-right: 0.5em; 100 padding-right: 0.5em;
101} 101}
102 102
103td#crumb, td#search { 103td#crumb, td#search {
104 color: #ccc; 104 color: #ccc;
105 border-top: solid 3px #555; 105 border-top: solid 3px #555;
106 background-color: #666; 106 background-color: #666;
107 border-bottom: solid 1px #333; 107 border-bottom: solid 1px #333;
108 padding: 2px 1em; 108 padding: 2px 1em;
109} 109}
110 110
111td#crumb { 111td#crumb {
112 font-weight: bold; 112 font-weight: bold;
113} 113}
114 114
115td#crumb a { 115td#crumb a {
116 color: #ccc; 116 color: #ccc;
117} 117}
118 118
119td#crumb a:hover { 119td#crumb a:hover {
120 color: #eee; 120 color: #eee;
121} 121}
122 122
123td#search { 123td#search {
124 text-align: right; 124 text-align: right;
125 vertical-align: center; 125 vertical-align: center;
126 padding-right: 0.5em; 126 padding-right: 0.5em;
127} 127}
128 128
129td#search form { 129td#search form {
130 margin: 0px; 130 margin: 0px;
131 padding: 0px; 131 padding: 0px;
132} 132}
133 133
134td#search input { 134td#search input {
135 font-size: 9pt; 135 font-size: 9pt;
136 padding: 0px; 136 padding: 0px;
137 width: 10em; 137 width: 10em;
138 border: solid 1px #333; 138 border: solid 1px #333;
139 color: #333; 139 color: #333;
140 background-color: #fff; 140 background-color: #fff;
141} 141}
142 142
143td#summary { 143div#summary {
144 vertical-align: top; 144 vertical-align: top;
145 padding-bottom: 1em; 145 margin-bottom: 1em;
146} 146}
147 147
148td#archivelist { 148table#downloads {
149 padding-bottom: 1em;
150}
151
152td#archivelist table {
153 float: right; 149 float: right;
154 border-collapse: collapse; 150 border-collapse: collapse;
155 border: solid 1px #777; 151 border: solid 1px #777;
152 margin-left: 0.5em;
153 margin-bottom: 0.5em;
156} 154}
157 155
158td#archivelist table th { 156table#downloads th {
159 background-color: #ccc; 157 background-color: #ccc;
160} 158}
161 159
162td#content { 160td#content {
163 padding: 1em 0.5em; 161 padding: 1em 0.5em;
164} 162}
165 163
166div#blob { 164div#blob {
167 border: solid 1px black; 165 border: solid 1px black;
168} 166}
169 167
170div.error { 168div.error {
171 color: red; 169 color: red;
172 font-weight: bold; 170 font-weight: bold;
173 margin: 1em 2em; 171 margin: 1em 2em;
174} 172}
175 173
176td.ls-blob, td.ls-dir, td.ls-mod { 174td.ls-blob, td.ls-dir, td.ls-mod {
177 font-family: monospace; 175 font-family: monospace;
178} 176}
179 177
180div.ls-dir a { 178div.ls-dir a {
181 font-weight: bold; 179 font-weight: bold;
182} 180}
183 181
184th.filesize, td.filesize { 182th.filesize, td.filesize {
185 text-align: right; 183 text-align: right;
186} 184}
187 185
188td.filesize { 186td.filesize {
189 font-family: monospace; 187 font-family: monospace;
190} 188}
191 189
192td.links { 190td.links {
193 font-size: 80%; 191 font-size: 80%;
194 padding-left: 2em; 192 padding-left: 2em;
195} 193}
196 194
197td.filemode { 195td.filemode {
198 font-family: monospace; 196 font-family: monospace;
199} 197}
200 198
201td.blob { 199td.blob {
202 white-space: pre; 200 white-space: pre;
203 font-family: monospace; 201 font-family: monospace;
204 background-color: white; 202 background-color: white;
205} 203}
206 204
207table.nowrap td { 205table.nowrap td {
208 white-space: nowrap; 206 white-space: nowrap;
209} 207}
210 208
211table.commit-info { 209table.commit-info {
212 border-collapse: collapse; 210 border-collapse: collapse;
213 margin-top: 1.5em; 211 margin-top: 1.5em;
214} 212}
215 213
216table.commit-info th { 214table.commit-info th {
217 text-align: left; 215 text-align: left;
218 font-weight: normal; 216 font-weight: normal;
219 padding: 0.1em 1em 0.1em 0.1em; 217 padding: 0.1em 1em 0.1em 0.1em;
220} 218}
221 219
222table.commit-info td { 220table.commit-info td {
223 font-weight: normal; 221 font-weight: normal;
224 padding: 0.1em 1em 0.1em 0.1em; 222 padding: 0.1em 1em 0.1em 0.1em;
225} 223}
226 224
227div.commit-subject { 225div.commit-subject {
228 font-weight: bold; 226 font-weight: bold;
229 font-size: 125%; 227 font-size: 125%;
230 margin: 1.5em 0em 0.5em 0em; 228 margin: 1.5em 0em 0.5em 0em;
231 padding: 0em; 229 padding: 0em;
232} 230}
233 231
234div.commit-msg { 232div.commit-msg {
235 white-space: pre; 233 white-space: pre;
236 font-family: monospace; 234 font-family: monospace;
237} 235}
238 236
239div.diffstat-header { 237div.diffstat-header {
240 font-weight: bold; 238 font-weight: bold;
241 padding-top: 1.5em; 239 padding-top: 1.5em;
242} 240}
243 241
244table.diffstat { 242table.diffstat {
245 border-collapse: collapse; 243 border-collapse: collapse;
246 width: 100%; 244 width: 100%;
247 border: solid 1px #aaa; 245 border: solid 1px #aaa;
248 background-color: #eee; 246 background-color: #eee;
249} 247}
250 248
251table.diffstat tr:hover { 249table.diffstat tr:hover {
252 background-color: #ccc; 250 background-color: #ccc;
253} 251}
254 252
255table.diffstat th { 253table.diffstat th {
256 font-weight: normal; 254 font-weight: normal;
257 text-align: left; 255 text-align: left;
258 text-decoration: underline; 256 text-decoration: underline;
259 padding: 0.1em 1em 0.1em 0.1em; 257 padding: 0.1em 1em 0.1em 0.1em;
260 font-size: 100%; 258 font-size: 100%;
261} 259}
262 260
263table.diffstat td { 261table.diffstat td {
264 padding: 0.2em 0.2em 0.1em 0.1em; 262 padding: 0.2em 0.2em 0.1em 0.1em;
265 font-size: 100%; 263 font-size: 100%;
266 border: none; 264 border: none;
267} 265}
268 266
269table.diffstat td.mode { 267table.diffstat td.mode {
270 white-space: nowrap; 268 white-space: nowrap;
271} 269}
272 270
273table.diffstat td span.modechange { 271table.diffstat td span.modechange {
274 padding-left: 1em; 272 padding-left: 1em;
275 color: red; 273 color: red;
276} 274}
277 275
278table.diffstat td.add a { 276table.diffstat td.add a {
279 color: green; 277 color: green;
280} 278}
281 279
282table.diffstat td.del a { 280table.diffstat td.del a {
283 color: red; 281 color: red;
284} 282}
285 283
286table.diffstat td.upd a { 284table.diffstat td.upd a {
287 color: blue; 285 color: blue;
288} 286}
289 287
290table.diffstat td.graph { 288table.diffstat td.graph {
291 width: 75%; 289 width: 75%;
292 vertical-align: center; 290 vertical-align: center;
293} 291}
294 292
295table.diffstat td.graph table { 293table.diffstat td.graph table {
296 border: none; 294 border: none;
297} 295}
298 296
299table.diffstat td.graph td { 297table.diffstat td.graph td {
300 padding: 0px; 298 padding: 0px;
301 border: 0px; 299 border: 0px;
302 height: 7pt; 300 height: 7pt;
303} 301}
304 302
305table.diffstat td.graph td.add { 303table.diffstat td.graph td.add {
306 background-color: #5c5; 304 background-color: #5c5;
307} 305}
308 306
309table.diffstat td.graph td.rem { 307table.diffstat td.graph td.rem {
310 background-color: #c55; 308 background-color: #c55;
311} 309}
312 310
313table.diffstat td.graph td.none { 311table.diffstat td.graph td.none {
314 background-color: none; 312 background-color: none;
315} 313}
316 314
317div.diffstat-summary { 315div.diffstat-summary {
318 color: #888; 316 color: #888;
319 padding-top: 0.5em; 317 padding-top: 0.5em;
320} 318}
321 319
322table.diff td { 320table.diff td {
323 font-family: monospace; 321 font-family: monospace;
324 white-space: pre; 322 white-space: pre;
325} 323}
326 324
327table.diff td div.head { 325table.diff td div.head {
328 font-weight: bold; 326 font-weight: bold;
329 padding-top: 1em; 327 padding-top: 1em;
330} 328}
331 329
332table.diff td div.hunk { 330table.diff td div.hunk {
333 color: #009; 331 color: #009;
334} 332}
335 333
336table.diff td div.add { 334table.diff td div.add {
337 color: green; 335 color: green;
338} 336}
339 337
340table.diff td div.del { 338table.diff td div.del {
341 color: red; 339 color: red;
342} 340}
343 341
344.sha1 { 342.sha1 {
345 font-family: courier; 343 font-family: courier;
346 font-size: 90%; 344 font-size: 90%;
347} 345}
348 346
349.left { 347.left {
350 text-align: left; 348 text-align: left;
351} 349}
352 350
353.right { 351.right {
354 text-align: right; 352 text-align: right;
355} 353}
356 354
357table.list td.repogroup { 355table.list td.repogroup {
358 font-style: italic; 356 font-style: italic;
359 color: #888; 357 color: #888;
360} 358}
361 359
362a.button { 360a.button {
363 font-size: 80%; 361 font-size: 80%;
364 color: #333; 362 color: #333;
365 background-color: #ccc; 363 background-color: #ccc;
366 border: solid 1px #999; 364 border: solid 1px #999;
367 padding: 0em 0.5em; 365 padding: 0em 0.5em;
368 margin: 0.1em 0.25em; 366 margin: 0.1em 0.25em;
369} 367}
370 368
371a.button:hover { 369a.button:hover {
372 text-decoration: none; 370 text-decoration: none;
373 background-color: #eee; 371 background-color: #eee;
374} 372}
375 373
376a.primary { 374a.primary {
377 font-size: 100%; 375 font-size: 100%;
378} 376}
379 377
380a.secondary { 378a.secondary {
381 font-size: 90%; 379 font-size: 90%;
382} 380}
383 381
384td.toplevel-repo { 382td.toplevel-repo {
385 383
386} 384}
387 385
388table.list td.sublevel-repo { 386table.list td.sublevel-repo {
389 padding-left: 1.5em; 387 padding-left: 1.5em;
390} 388}
391 389
392span.age-mins { 390span.age-mins {
393 font-weight: bold; 391 font-weight: bold;
394 color: #080; 392 color: #080;
395} 393}
396 394
397span.age-hours { 395span.age-hours {
398 color: #080; 396 color: #080;
399} 397}
400 398
401span.age-days { 399span.age-days {
402 color: #040; 400 color: #040;
403} 401}
404 402
405span.age-weeks { 403span.age-weeks {
406 color: #444; 404 color: #444;
407} 405}
408 406
409span.age-months { 407span.age-months {
410 color: #888; 408 color: #888;
411} 409}
412 410
413span.age-years { 411span.age-years {
414 color: #bbb; 412 color: #bbb;
diff --git a/cgit.h b/cgit.h
index 3938633..5c55bec 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,226 +1,227 @@
1#ifndef CGIT_H 1#ifndef CGIT_H
2#define CGIT_H 2#define CGIT_H
3 3
4 4
5#include <git-compat-util.h> 5#include <git-compat-util.h>
6#include <cache.h> 6#include <cache.h>
7#include <grep.h> 7#include <grep.h>
8#include <object.h> 8#include <object.h>
9#include <tree.h> 9#include <tree.h>
10#include <commit.h> 10#include <commit.h>
11#include <tag.h> 11#include <tag.h>
12#include <diff.h> 12#include <diff.h>
13#include <diffcore.h> 13#include <diffcore.h>
14#include <refs.h> 14#include <refs.h>
15#include <revision.h> 15#include <revision.h>
16#include <log-tree.h> 16#include <log-tree.h>
17#include <archive.h> 17#include <archive.h>
18#include <xdiff/xdiff.h> 18#include <xdiff/xdiff.h>
19 19
20 20
21/* 21/*
22 * The valid cgit repo-commands 22 * The valid cgit repo-commands
23 */ 23 */
24#define CMD_LOG 1 24#define CMD_LOG 1
25#define CMD_COMMIT 2 25#define CMD_COMMIT 2
26#define CMD_DIFF 3 26#define CMD_DIFF 3
27#define CMD_TREE 4 27#define CMD_TREE 4
28#define CMD_VIEW 5 28#define CMD_VIEW 5
29#define CMD_BLOB 6 29#define CMD_BLOB 6
30#define CMD_SNAPSHOT 7 30#define CMD_SNAPSHOT 7
31 31
32 32
33/* 33/*
34 * Dateformats used on misc. pages 34 * Dateformats used on misc. pages
35 */ 35 */
36#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S" 36#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S"
37#define FMT_SHORTDATE "%Y-%m-%d" 37#define FMT_SHORTDATE "%Y-%m-%d"
38 38
39 39
40/* 40/*
41 * Limits used for relative dates 41 * Limits used for relative dates
42 */ 42 */
43#define TM_MIN 60 43#define TM_MIN 60
44#define TM_HOUR (TM_MIN * 60) 44#define TM_HOUR (TM_MIN * 60)
45#define TM_DAY (TM_HOUR * 24) 45#define TM_DAY (TM_HOUR * 24)
46#define TM_WEEK (TM_DAY * 7) 46#define TM_WEEK (TM_DAY * 7)
47#define TM_YEAR (TM_DAY * 365) 47#define TM_YEAR (TM_DAY * 365)
48#define TM_MONTH (TM_YEAR / 12.0) 48#define TM_MONTH (TM_YEAR / 12.0)
49 49
50 50
51typedef void (*configfn)(const char *name, const char *value); 51typedef void (*configfn)(const char *name, const char *value);
52typedef void (*filepair_fn)(struct diff_filepair *pair); 52typedef void (*filepair_fn)(struct diff_filepair *pair);
53typedef void (*linediff_fn)(char *line, int len); 53typedef void (*linediff_fn)(char *line, int len);
54 54
55struct cacheitem { 55struct cacheitem {
56 char *name; 56 char *name;
57 struct stat st; 57 struct stat st;
58 int ttl; 58 int ttl;
59 int fd; 59 int fd;
60}; 60};
61 61
62struct repoinfo { 62struct repoinfo {
63 char *url; 63 char *url;
64 char *name; 64 char *name;
65 char *path; 65 char *path;
66 char *desc; 66 char *desc;
67 char *owner; 67 char *owner;
68 char *defbranch; 68 char *defbranch;
69 char *group; 69 char *group;
70 char *module_link; 70 char *module_link;
71 char *readme;
71 int snapshots; 72 int snapshots;
72 int enable_log_filecount; 73 int enable_log_filecount;
73 int enable_log_linecount; 74 int enable_log_linecount;
74}; 75};
75 76
76struct repolist { 77struct repolist {
77 int length; 78 int length;
78 int count; 79 int count;
79 struct repoinfo *repos; 80 struct repoinfo *repos;
80}; 81};
81 82
82struct commitinfo { 83struct commitinfo {
83 struct commit *commit; 84 struct commit *commit;
84 char *author; 85 char *author;
85 char *author_email; 86 char *author_email;
86 unsigned long author_date; 87 unsigned long author_date;
87 char *committer; 88 char *committer;
88 char *committer_email; 89 char *committer_email;
89 unsigned long committer_date; 90 unsigned long committer_date;
90 char *subject; 91 char *subject;
91 char *msg; 92 char *msg;
92}; 93};
93 94
94struct taginfo { 95struct taginfo {
95 char *tagger; 96 char *tagger;
96 char *tagger_email; 97 char *tagger_email;
97 int tagger_date; 98 int tagger_date;
98 char *msg; 99 char *msg;
99}; 100};
100 101
101extern const char cgit_version[]; 102extern const char cgit_version[];
102 103
103extern struct repolist cgit_repolist; 104extern struct repolist cgit_repolist;
104extern struct repoinfo *cgit_repo; 105extern struct repoinfo *cgit_repo;
105extern int cgit_cmd; 106extern int cgit_cmd;
106 107
107extern char *cgit_root_title; 108extern char *cgit_root_title;
108extern char *cgit_css; 109extern char *cgit_css;
109extern char *cgit_logo; 110extern char *cgit_logo;
110extern char *cgit_index_header; 111extern char *cgit_index_header;
111extern char *cgit_logo_link; 112extern char *cgit_logo_link;
112extern char *cgit_module_link; 113extern char *cgit_module_link;
113extern char *cgit_agefile; 114extern char *cgit_agefile;
114extern char *cgit_virtual_root; 115extern char *cgit_virtual_root;
115extern char *cgit_script_name; 116extern char *cgit_script_name;
116extern char *cgit_cache_root; 117extern char *cgit_cache_root;
117extern char *cgit_repo_group; 118extern char *cgit_repo_group;
118 119
119extern int cgit_nocache; 120extern int cgit_nocache;
120extern int cgit_snapshots; 121extern int cgit_snapshots;
121extern int cgit_enable_log_filecount; 122extern int cgit_enable_log_filecount;
122extern int cgit_enable_log_linecount; 123extern int cgit_enable_log_linecount;
123extern int cgit_max_lock_attempts; 124extern int cgit_max_lock_attempts;
124extern int cgit_cache_root_ttl; 125extern int cgit_cache_root_ttl;
125extern int cgit_cache_repo_ttl; 126extern int cgit_cache_repo_ttl;
126extern int cgit_cache_dynamic_ttl; 127extern int cgit_cache_dynamic_ttl;
127extern int cgit_cache_static_ttl; 128extern int cgit_cache_static_ttl;
128extern int cgit_cache_max_create_time; 129extern int cgit_cache_max_create_time;
129 130
130extern int cgit_max_msg_len; 131extern int cgit_max_msg_len;
131extern int cgit_max_repodesc_len; 132extern int cgit_max_repodesc_len;
132extern int cgit_max_commit_count; 133extern int cgit_max_commit_count;
133 134
134extern int cgit_query_has_symref; 135extern int cgit_query_has_symref;
135extern int cgit_query_has_sha1; 136extern int cgit_query_has_sha1;
136 137
137extern char *cgit_querystring; 138extern char *cgit_querystring;
138extern char *cgit_query_repo; 139extern char *cgit_query_repo;
139extern char *cgit_query_page; 140extern char *cgit_query_page;
140extern char *cgit_query_search; 141extern char *cgit_query_search;
141extern char *cgit_query_head; 142extern char *cgit_query_head;
142extern char *cgit_query_sha1; 143extern char *cgit_query_sha1;
143extern char *cgit_query_sha2; 144extern char *cgit_query_sha2;
144extern char *cgit_query_path; 145extern char *cgit_query_path;
145extern char *cgit_query_name; 146extern char *cgit_query_name;
146extern int cgit_query_ofs; 147extern int cgit_query_ofs;
147 148
148extern int htmlfd; 149extern int htmlfd;
149 150
150extern int cgit_get_cmd_index(const char *cmd); 151extern int cgit_get_cmd_index(const char *cmd);
151extern struct repoinfo *cgit_get_repoinfo(const char *url); 152extern struct repoinfo *cgit_get_repoinfo(const char *url);
152extern void cgit_global_config_cb(const char *name, const char *value); 153extern void cgit_global_config_cb(const char *name, const char *value);
153extern void cgit_repo_config_cb(const char *name, const char *value); 154extern void cgit_repo_config_cb(const char *name, const char *value);
154extern void cgit_querystring_cb(const char *name, const char *value); 155extern void cgit_querystring_cb(const char *name, const char *value);
155 156
156extern int chk_zero(int result, char *msg); 157extern int chk_zero(int result, char *msg);
157extern int chk_positive(int result, char *msg); 158extern int chk_positive(int result, char *msg);
158 159
159extern int hextoint(char c); 160extern int hextoint(char c);
160 161
161extern void *cgit_free_commitinfo(struct commitinfo *info); 162extern void *cgit_free_commitinfo(struct commitinfo *info);
162 163
163extern int cgit_diff_files(const unsigned char *old_sha1, 164extern int cgit_diff_files(const unsigned char *old_sha1,
164 const unsigned char *new_sha1, 165 const unsigned char *new_sha1,
165 linediff_fn fn); 166 linediff_fn fn);
166 167
167extern void cgit_diff_tree(const unsigned char *old_sha1, 168extern void cgit_diff_tree(const unsigned char *old_sha1,
168 const unsigned char *new_sha1, 169 const unsigned char *new_sha1,
169 filepair_fn fn); 170 filepair_fn fn);
170 171
171extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 172extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
172 173
173extern char *fmt(const char *format,...); 174extern char *fmt(const char *format,...);
174 175
175extern void html(const char *txt); 176extern void html(const char *txt);
176extern void htmlf(const char *format,...); 177extern void htmlf(const char *format,...);
177extern void html_txt(char *txt); 178extern void html_txt(char *txt);
178extern void html_ntxt(int len, char *txt); 179extern void html_ntxt(int len, char *txt);
179extern void html_attr(char *txt); 180extern void html_attr(char *txt);
180extern void html_hidden(char *name, char *value); 181extern void html_hidden(char *name, char *value);
181extern void html_link_open(char *url, char *title, char *class); 182extern void html_link_open(char *url, char *title, char *class);
182extern void html_link_close(void); 183extern void html_link_close(void);
183extern void html_filemode(unsigned short mode); 184extern void html_filemode(unsigned short mode);
184extern int html_include(const char *filename); 185extern int html_include(const char *filename);
185 186
186extern int cgit_read_config(const char *filename, configfn fn); 187extern int cgit_read_config(const char *filename, configfn fn);
187extern int cgit_parse_query(char *txt, configfn fn); 188extern int cgit_parse_query(char *txt, configfn fn);
188extern struct commitinfo *cgit_parse_commit(struct commit *commit); 189extern struct commitinfo *cgit_parse_commit(struct commit *commit);
189extern struct taginfo *cgit_parse_tag(struct tag *tag); 190extern struct taginfo *cgit_parse_tag(struct tag *tag);
190extern void cgit_parse_url(const char *url); 191extern void cgit_parse_url(const char *url);
191 192
192extern char *cache_safe_filename(const char *unsafe); 193extern char *cache_safe_filename(const char *unsafe);
193extern int cache_lock(struct cacheitem *item); 194extern int cache_lock(struct cacheitem *item);
194extern int cache_unlock(struct cacheitem *item); 195extern int cache_unlock(struct cacheitem *item);
195extern int cache_cancel_lock(struct cacheitem *item); 196extern int cache_cancel_lock(struct cacheitem *item);
196extern int cache_exist(struct cacheitem *item); 197extern int cache_exist(struct cacheitem *item);
197extern int cache_expired(struct cacheitem *item); 198extern int cache_expired(struct cacheitem *item);
198 199
199extern char *cgit_repourl(const char *reponame); 200extern char *cgit_repourl(const char *reponame);
200extern char *cgit_pageurl(const char *reponame, const char *pagename, 201extern char *cgit_pageurl(const char *reponame, const char *pagename,
201 const char *query); 202 const char *query);
202 203
203extern void cgit_print_error(char *msg); 204extern void cgit_print_error(char *msg);
204extern void cgit_print_date(time_t secs, char *format); 205extern void cgit_print_date(time_t secs, char *format);
205extern void cgit_print_age(time_t t, time_t max_relative, char *format); 206extern void cgit_print_age(time_t t, time_t max_relative, char *format);
206extern void cgit_print_docstart(char *title, struct cacheitem *item); 207extern void cgit_print_docstart(char *title, struct cacheitem *item);
207extern void cgit_print_docend(); 208extern void cgit_print_docend();
208extern void cgit_print_pageheader(char *title, int show_search); 209extern void cgit_print_pageheader(char *title, int show_search);
209extern void cgit_print_snapshot_start(const char *mimetype, 210extern void cgit_print_snapshot_start(const char *mimetype,
210 const char *filename, 211 const char *filename,
211 struct cacheitem *item); 212 struct cacheitem *item);
212 213
213extern void cgit_print_repolist(struct cacheitem *item); 214extern void cgit_print_repolist(struct cacheitem *item);
214extern void cgit_print_summary(); 215extern void cgit_print_summary();
215extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path); 216extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path);
216extern void cgit_print_view(const char *hex, char *path); 217extern void cgit_print_view(const char *hex, char *path);
217extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); 218extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path);
218extern void cgit_print_tree(const char *rev, const char *hex, char *path); 219extern void cgit_print_tree(const char *rev, const char *hex, char *path);
219extern void cgit_print_commit(const char *hex); 220extern void cgit_print_commit(const char *hex);
220extern void cgit_print_diff(const char *head, const char *old_hex, const char *new_hex, 221extern void cgit_print_diff(const char *head, const char *old_hex, const char *new_hex,
221 char *path); 222 char *path);
222extern void cgit_print_snapshot(struct cacheitem *item, const char *hex, 223extern void cgit_print_snapshot(struct cacheitem *item, const char *hex,
223 const char *format, const char *prefix, 224 const char *format, const char *prefix,
224 const char *filename); 225 const char *filename);
225 226
226#endif /* CGIT_H */ 227#endif /* CGIT_H */
diff --git a/cgitrc b/cgitrc
index eaa9ce3..054a708 100644
--- a/cgitrc
+++ b/cgitrc
@@ -1,110 +1,111 @@
1## 1##
2## cgitrc: template for /etc/cgitrc 2## cgitrc: template for /etc/cgitrc
3## 3##
4 4
5 5
6## Uncomment and set to 1 to deactivate caching of generated pages. Mostly 6## Uncomment and set to 1 to deactivate caching of generated pages. Mostly
7## usefull for testing. 7## usefull for testing.
8#nocache=0 8#nocache=0
9 9
10 10
11## Enable/disable snapshots by default. This can be overridden per repo 11## Enable/disable snapshots by default. This can be overridden per repo
12#snapshots=0 12#snapshots=0
13 13
14 14
15## Enable/disable display of 'number of files changed' in log view 15## Enable/disable display of 'number of files changed' in log view
16#enable-log-filecount=0 16#enable-log-filecount=0
17 17
18 18
19## Enable/disable display of 'number of lines changed' in log view 19## Enable/disable display of 'number of lines changed' in log view
20#enable-log-linecount=0 20#enable-log-linecount=0
21 21
22 22
23## Specify a root for virtual urls. This makes cgit generate urls like 23## Specify a root for virtual urls. This makes cgit generate urls like
24## 24##
25## http://localhost/git/repo/log/?id=master 25## http://localhost/git/repo/log/?id=master
26## 26##
27## instead of 27## instead of
28## 28##
29## http://localhost/cgit/cgit.cgi?r=repo&p=log&id=master 29## http://localhost/cgit/cgit.cgi?r=repo&p=log&id=master
30## 30##
31## For this to work with apache, rewrite rules must be added to httpd.conf, 31## For this to work with apache, rewrite rules must be added to httpd.conf,
32## possibly looking something like this: 32## possibly looking something like this:
33## 33##
34## RewriteRule ^/git/$ /cgit/cgit.cgi [L,QSA] 34## RewriteRule ^/git/$ /cgit/cgit.cgi [L,QSA]
35## RewriteRule ^/git/([^/]+)/$ /cgit/cgit.cgi?r=$1 [L,QSA] 35## RewriteRule ^/git/([^/]+)/$ /cgit/cgit.cgi?r=$1 [L,QSA]
36## RewriteRule ^/git/([^/]+)/([^/]+)/$ /cgit/cgit.cgi?r=$1&p=$2 [L,QSA] 36## RewriteRule ^/git/([^/]+)/([^/]+)/$ /cgit/cgit.cgi?r=$1&p=$2 [L,QSA]
37## 37##
38## This setting is disabled by default. 38## This setting is disabled by default.
39#virtual-root=/git 39#virtual-root=/git
40 40
41 41
42## Set the title printed on the root page 42## Set the title printed on the root page
43#root-title=Git repository browser 43#root-title=Git repository browser
44 44
45 45
46## Link to css file 46## Link to css file
47#css=/cgit/cgit.css 47#css=/cgit/cgit.css
48 48
49 49
50## Link to logo file 50## Link to logo file
51#logo=/cgit/git-logo.png 51#logo=/cgit/git-logo.png
52 52
53 53
54## Url loaded when clicking the logo 54## Url loaded when clicking the logo
55#logo-link=http://www.kernel.org/pub/software/scm/git/docs/ 55#logo-link=http://www.kernel.org/pub/software/scm/git/docs/
56 56
57 57
58## Url loaded when clicking a submodule link 58## Url loaded when clicking a submodule link
59#module-link=./?repo=%s&page=commit&id=%s 59#module-link=./?repo=%s&page=commit&id=%s
60 60
61 61
62## Number of chars shown of repo description (in repolist view) 62## Number of chars shown of repo description (in repolist view)
63#max-repodesc-length=60 63#max-repodesc-length=60
64 64
65 65
66## Number of chars shown of commit subject message (in log view) 66## Number of chars shown of commit subject message (in log view)
67#max-message-length=60 67#max-message-length=60
68 68
69 69
70## Number of commits per page in log view 70## Number of commits per page in log view
71#max-commit-count=50 71#max-commit-count=50
72 72
73 73
74## Root of cached output 74## Root of cached output
75#cache-root=/var/cache/cgit 75#cache-root=/var/cache/cgit
76 76
77 77
78## Include another config-file 78## Include another config-file
79#include=/var/cgit/repolist 79#include=/var/cgit/repolist
80 80
81## 81##
82## Time-To-Live settings: specifies how long (in minutes) different pages 82## Time-To-Live settings: specifies how long (in minutes) different pages
83## should be cached (0 for instant expiration, -1 for immortal pages) 83## should be cached (0 for instant expiration, -1 for immortal pages)
84## 84##
85 85
86## ttl for root page 86## ttl for root page
87#cache-root-ttl=5 87#cache-root-ttl=5
88 88
89## ttl for repo summary page 89## ttl for repo summary page
90#cache-repo-ttl=5 90#cache-repo-ttl=5
91 91
92## ttl for other dynamic pages 92## ttl for other dynamic pages
93#cache-dynamic-ttl=5 93#cache-dynamic-ttl=5
94 94
95## ttl for static pages (addressed by SHA-1) 95## ttl for static pages (addressed by SHA-1)
96#cache-static-ttl=-1 96#cache-static-ttl=-1
97 97
98 98
99 99
100## Example repository entry. Required values are repo.url and repo.path (each 100## Example repository entry. Required values are repo.url and repo.path (each
101## repository section must start with repo.url). 101## repository section must start with repo.url).
102#repo.url=cgit 102#repo.url=cgit
103#repo.name=cgit 103#repo.name=cgit
104#repo.desc=the caching cgi for git 104#repo.desc=the caching cgi for git
105#repo.path=/pub/git/cgit 105#repo.path=/pub/git/cgit
106#repo.owner=Lars Hjemli 106#repo.owner=Lars Hjemli
107 #repo.snapshots=1 # override a sitewide snapshot-setting 107 #repo.snapshots=1 # override a sitewide snapshot-setting
108 #repo.enable-log-filecount=0 # override the default filecount setting 108 #repo.enable-log-filecount=0 # override the default filecount setting
109 #repo.enable-log-linecount=0 # override the default linecount setting 109 #repo.enable-log-linecount=0 # override the default linecount setting
110 #repo.module-link=/git/%s/commit/?id=%s # override the standard module-link 110 #repo.module-link=/git/%s/commit/?id=%s # override the standard module-link
111 #repo.readme=info/web/readme # specify a file to include on summary page
diff --git a/shared.c b/shared.c
index ce3ca4f..e3123a8 100644
--- a/shared.c
+++ b/shared.c
@@ -1,368 +1,374 @@
1/* shared.c: global vars + some callback functions 1/* shared.c: global vars + some callback functions
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 "cgit.h" 9#include "cgit.h"
10 10
11struct repolist cgit_repolist; 11struct repolist cgit_repolist;
12struct repoinfo *cgit_repo; 12struct repoinfo *cgit_repo;
13int cgit_cmd; 13int cgit_cmd;
14 14
15char *cgit_root_title = "Git repository browser"; 15char *cgit_root_title = "Git repository browser";
16char *cgit_css = "/cgit.css"; 16char *cgit_css = "/cgit.css";
17char *cgit_logo = "/git-logo.png"; 17char *cgit_logo = "/git-logo.png";
18char *cgit_index_header = NULL; 18char *cgit_index_header = NULL;
19char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/"; 19char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/";
20char *cgit_module_link = "./?repo=%s&page=commit&id=%s"; 20char *cgit_module_link = "./?repo=%s&page=commit&id=%s";
21char *cgit_agefile = "info/web/last-modified"; 21char *cgit_agefile = "info/web/last-modified";
22char *cgit_virtual_root = NULL; 22char *cgit_virtual_root = NULL;
23char *cgit_script_name = CGIT_SCRIPT_NAME; 23char *cgit_script_name = CGIT_SCRIPT_NAME;
24char *cgit_cache_root = "/var/cache/cgit"; 24char *cgit_cache_root = "/var/cache/cgit";
25char *cgit_repo_group = NULL; 25char *cgit_repo_group = NULL;
26 26
27int cgit_nocache = 0; 27int cgit_nocache = 0;
28int cgit_snapshots = 0; 28int cgit_snapshots = 0;
29int cgit_enable_log_filecount = 0; 29int cgit_enable_log_filecount = 0;
30int cgit_enable_log_linecount = 0; 30int cgit_enable_log_linecount = 0;
31int cgit_max_lock_attempts = 5; 31int cgit_max_lock_attempts = 5;
32int cgit_cache_root_ttl = 5; 32int cgit_cache_root_ttl = 5;
33int cgit_cache_repo_ttl = 5; 33int cgit_cache_repo_ttl = 5;
34int cgit_cache_dynamic_ttl = 5; 34int cgit_cache_dynamic_ttl = 5;
35int cgit_cache_static_ttl = -1; 35int cgit_cache_static_ttl = -1;
36int cgit_cache_max_create_time = 5; 36int cgit_cache_max_create_time = 5;
37 37
38int cgit_max_msg_len = 60; 38int cgit_max_msg_len = 60;
39int cgit_max_repodesc_len = 60; 39int cgit_max_repodesc_len = 60;
40int cgit_max_commit_count = 50; 40int cgit_max_commit_count = 50;
41 41
42int cgit_query_has_symref = 0; 42int cgit_query_has_symref = 0;
43int cgit_query_has_sha1 = 0; 43int cgit_query_has_sha1 = 0;
44 44
45char *cgit_querystring = NULL; 45char *cgit_querystring = NULL;
46char *cgit_query_repo = NULL; 46char *cgit_query_repo = NULL;
47char *cgit_query_page = NULL; 47char *cgit_query_page = NULL;
48char *cgit_query_head = NULL; 48char *cgit_query_head = NULL;
49char *cgit_query_search = NULL; 49char *cgit_query_search = NULL;
50char *cgit_query_sha1 = NULL; 50char *cgit_query_sha1 = NULL;
51char *cgit_query_sha2 = NULL; 51char *cgit_query_sha2 = NULL;
52char *cgit_query_path = NULL; 52char *cgit_query_path = NULL;
53char *cgit_query_name = NULL; 53char *cgit_query_name = NULL;
54int cgit_query_ofs = 0; 54int cgit_query_ofs = 0;
55 55
56int htmlfd = 0; 56int htmlfd = 0;
57 57
58 58
59int cgit_get_cmd_index(const char *cmd) 59int cgit_get_cmd_index(const char *cmd)
60{ 60{
61 static char *cmds[] = {"log", "commit", "diff", "tree", "view", "blob", "snapshot", NULL}; 61 static char *cmds[] = {"log", "commit", "diff", "tree", "view", "blob", "snapshot", NULL};
62 int i; 62 int i;
63 63
64 for(i = 0; cmds[i]; i++) 64 for(i = 0; cmds[i]; i++)
65 if (!strcmp(cmd, cmds[i])) 65 if (!strcmp(cmd, cmds[i]))
66 return i + 1; 66 return i + 1;
67 return 0; 67 return 0;
68} 68}
69 69
70int chk_zero(int result, char *msg) 70int chk_zero(int result, char *msg)
71{ 71{
72 if (result != 0) 72 if (result != 0)
73 die("%s: %s", msg, strerror(errno)); 73 die("%s: %s", msg, strerror(errno));
74 return result; 74 return result;
75} 75}
76 76
77int chk_positive(int result, char *msg) 77int chk_positive(int result, char *msg)
78{ 78{
79 if (result <= 0) 79 if (result <= 0)
80 die("%s: %s", msg, strerror(errno)); 80 die("%s: %s", msg, strerror(errno));
81 return result; 81 return result;
82} 82}
83 83
84struct repoinfo *add_repo(const char *url) 84struct repoinfo *add_repo(const char *url)
85{ 85{
86 struct repoinfo *ret; 86 struct repoinfo *ret;
87 87
88 if (++cgit_repolist.count > cgit_repolist.length) { 88 if (++cgit_repolist.count > cgit_repolist.length) {
89 if (cgit_repolist.length == 0) 89 if (cgit_repolist.length == 0)
90 cgit_repolist.length = 8; 90 cgit_repolist.length = 8;
91 else 91 else
92 cgit_repolist.length *= 2; 92 cgit_repolist.length *= 2;
93 cgit_repolist.repos = xrealloc(cgit_repolist.repos, 93 cgit_repolist.repos = xrealloc(cgit_repolist.repos,
94 cgit_repolist.length * 94 cgit_repolist.length *
95 sizeof(struct repoinfo)); 95 sizeof(struct repoinfo));
96 } 96 }
97 97
98 ret = &cgit_repolist.repos[cgit_repolist.count-1]; 98 ret = &cgit_repolist.repos[cgit_repolist.count-1];
99 ret->url = xstrdup(url); 99 ret->url = xstrdup(url);
100 ret->name = ret->url; 100 ret->name = ret->url;
101 ret->path = NULL; 101 ret->path = NULL;
102 ret->desc = NULL; 102 ret->desc = NULL;
103 ret->owner = NULL; 103 ret->owner = NULL;
104 ret->group = cgit_repo_group; 104 ret->group = cgit_repo_group;
105 ret->defbranch = "master"; 105 ret->defbranch = "master";
106 ret->snapshots = cgit_snapshots; 106 ret->snapshots = cgit_snapshots;
107 ret->enable_log_filecount = cgit_enable_log_filecount; 107 ret->enable_log_filecount = cgit_enable_log_filecount;
108 ret->enable_log_linecount = cgit_enable_log_linecount; 108 ret->enable_log_linecount = cgit_enable_log_linecount;
109 ret->module_link = cgit_module_link; 109 ret->module_link = cgit_module_link;
110 ret->readme = NULL;
110 return ret; 111 return ret;
111} 112}
112 113
113struct repoinfo *cgit_get_repoinfo(const char *url) 114struct repoinfo *cgit_get_repoinfo(const char *url)
114{ 115{
115 int i; 116 int i;
116 struct repoinfo *repo; 117 struct repoinfo *repo;
117 118
118 for (i=0; i<cgit_repolist.count; i++) { 119 for (i=0; i<cgit_repolist.count; i++) {
119 repo = &cgit_repolist.repos[i]; 120 repo = &cgit_repolist.repos[i];
120 if (!strcmp(repo->url, url)) 121 if (!strcmp(repo->url, url))
121 return repo; 122 return repo;
122 } 123 }
123 return NULL; 124 return NULL;
124} 125}
125 126
126void cgit_global_config_cb(const char *name, const char *value) 127void cgit_global_config_cb(const char *name, const char *value)
127{ 128{
128 if (!strcmp(name, "root-title")) 129 if (!strcmp(name, "root-title"))
129 cgit_root_title = xstrdup(value); 130 cgit_root_title = xstrdup(value);
130 else if (!strcmp(name, "css")) 131 else if (!strcmp(name, "css"))
131 cgit_css = xstrdup(value); 132 cgit_css = xstrdup(value);
132 else if (!strcmp(name, "logo")) 133 else if (!strcmp(name, "logo"))
133 cgit_logo = xstrdup(value); 134 cgit_logo = xstrdup(value);
134 else if (!strcmp(name, "index-header")) 135 else if (!strcmp(name, "index-header"))
135 cgit_index_header = xstrdup(value); 136 cgit_index_header = xstrdup(value);
136 else if (!strcmp(name, "logo-link")) 137 else if (!strcmp(name, "logo-link"))
137 cgit_logo_link = xstrdup(value); 138 cgit_logo_link = xstrdup(value);
138 else if (!strcmp(name, "module-link")) 139 else if (!strcmp(name, "module-link"))
139 cgit_module_link = xstrdup(value); 140 cgit_module_link = xstrdup(value);
140 else if (!strcmp(name, "virtual-root")) 141 else if (!strcmp(name, "virtual-root"))
141 cgit_virtual_root = xstrdup(value); 142 cgit_virtual_root = xstrdup(value);
142 else if (!strcmp(name, "nocache")) 143 else if (!strcmp(name, "nocache"))
143 cgit_nocache = atoi(value); 144 cgit_nocache = atoi(value);
144 else if (!strcmp(name, "snapshots")) 145 else if (!strcmp(name, "snapshots"))
145 cgit_snapshots = atoi(value); 146 cgit_snapshots = atoi(value);
146 else if (!strcmp(name, "enable-log-filecount")) 147 else if (!strcmp(name, "enable-log-filecount"))
147 cgit_enable_log_filecount = atoi(value); 148 cgit_enable_log_filecount = atoi(value);
148 else if (!strcmp(name, "enable-log-linecount")) 149 else if (!strcmp(name, "enable-log-linecount"))
149 cgit_enable_log_linecount = atoi(value); 150 cgit_enable_log_linecount = atoi(value);
150 else if (!strcmp(name, "cache-root")) 151 else if (!strcmp(name, "cache-root"))
151 cgit_cache_root = xstrdup(value); 152 cgit_cache_root = xstrdup(value);
152 else if (!strcmp(name, "cache-root-ttl")) 153 else if (!strcmp(name, "cache-root-ttl"))
153 cgit_cache_root_ttl = atoi(value); 154 cgit_cache_root_ttl = atoi(value);
154 else if (!strcmp(name, "cache-repo-ttl")) 155 else if (!strcmp(name, "cache-repo-ttl"))
155 cgit_cache_repo_ttl = atoi(value); 156 cgit_cache_repo_ttl = atoi(value);
156 else if (!strcmp(name, "cache-static-ttl")) 157 else if (!strcmp(name, "cache-static-ttl"))
157 cgit_cache_static_ttl = atoi(value); 158 cgit_cache_static_ttl = atoi(value);
158 else if (!strcmp(name, "cache-dynamic-ttl")) 159 else if (!strcmp(name, "cache-dynamic-ttl"))
159 cgit_cache_dynamic_ttl = atoi(value); 160 cgit_cache_dynamic_ttl = atoi(value);
160 else if (!strcmp(name, "max-message-length")) 161 else if (!strcmp(name, "max-message-length"))
161 cgit_max_msg_len = atoi(value); 162 cgit_max_msg_len = atoi(value);
162 else if (!strcmp(name, "max-repodesc-length")) 163 else if (!strcmp(name, "max-repodesc-length"))
163 cgit_max_repodesc_len = atoi(value); 164 cgit_max_repodesc_len = atoi(value);
164 else if (!strcmp(name, "max-commit-count")) 165 else if (!strcmp(name, "max-commit-count"))
165 cgit_max_commit_count = atoi(value); 166 cgit_max_commit_count = atoi(value);
166 else if (!strcmp(name, "agefile")) 167 else if (!strcmp(name, "agefile"))
167 cgit_agefile = xstrdup(value); 168 cgit_agefile = xstrdup(value);
168 else if (!strcmp(name, "repo.group")) 169 else if (!strcmp(name, "repo.group"))
169 cgit_repo_group = xstrdup(value); 170 cgit_repo_group = xstrdup(value);
170 else if (!strcmp(name, "repo.url")) 171 else if (!strcmp(name, "repo.url"))
171 cgit_repo = add_repo(value); 172 cgit_repo = add_repo(value);
172 else if (!strcmp(name, "repo.name")) 173 else if (!strcmp(name, "repo.name"))
173 cgit_repo->name = xstrdup(value); 174 cgit_repo->name = xstrdup(value);
174 else if (cgit_repo && !strcmp(name, "repo.path")) 175 else if (cgit_repo && !strcmp(name, "repo.path"))
175 cgit_repo->path = xstrdup(value); 176 cgit_repo->path = xstrdup(value);
176 else if (cgit_repo && !strcmp(name, "repo.desc")) 177 else if (cgit_repo && !strcmp(name, "repo.desc"))
177 cgit_repo->desc = xstrdup(value); 178 cgit_repo->desc = xstrdup(value);
178 else if (cgit_repo && !strcmp(name, "repo.owner")) 179 else if (cgit_repo && !strcmp(name, "repo.owner"))
179 cgit_repo->owner = xstrdup(value); 180 cgit_repo->owner = xstrdup(value);
180 else if (cgit_repo && !strcmp(name, "repo.defbranch")) 181 else if (cgit_repo && !strcmp(name, "repo.defbranch"))
181 cgit_repo->defbranch = xstrdup(value); 182 cgit_repo->defbranch = xstrdup(value);
182 else if (cgit_repo && !strcmp(name, "repo.snapshots")) 183 else if (cgit_repo && !strcmp(name, "repo.snapshots"))
183 cgit_repo->snapshots = cgit_snapshots * atoi(value); 184 cgit_repo->snapshots = cgit_snapshots * atoi(value);
184 else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount")) 185 else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount"))
185 cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value); 186 cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value);
186 else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount")) 187 else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount"))
187 cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value); 188 cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value);
188 else if (cgit_repo && !strcmp(name, "repo.module-link")) 189 else if (cgit_repo && !strcmp(name, "repo.module-link"))
189 cgit_repo->module_link= xstrdup(value); 190 cgit_repo->module_link= xstrdup(value);
190 else if (!strcmp(name, "include")) 191 else if (cgit_repo && !strcmp(name, "repo.readme") && value != NULL) {
192 if (*value == '/')
193 cgit_repo->readme = xstrdup(value);
194 else
195 cgit_repo->readme = xstrdup(fmt("%s/%s", cgit_repo->path, value));
196 } else if (!strcmp(name, "include"))
191 cgit_read_config(value, cgit_global_config_cb); 197 cgit_read_config(value, cgit_global_config_cb);
192} 198}
193 199
194void cgit_querystring_cb(const char *name, const char *value) 200void cgit_querystring_cb(const char *name, const char *value)
195{ 201{
196 if (!strcmp(name,"r")) { 202 if (!strcmp(name,"r")) {
197 cgit_query_repo = xstrdup(value); 203 cgit_query_repo = xstrdup(value);
198 cgit_repo = cgit_get_repoinfo(value); 204 cgit_repo = cgit_get_repoinfo(value);
199 } else if (!strcmp(name, "p")) { 205 } else if (!strcmp(name, "p")) {
200 cgit_query_page = xstrdup(value); 206 cgit_query_page = xstrdup(value);
201 cgit_cmd = cgit_get_cmd_index(value); 207 cgit_cmd = cgit_get_cmd_index(value);
202 } else if (!strcmp(name, "url")) { 208 } else if (!strcmp(name, "url")) {
203 cgit_parse_url(value); 209 cgit_parse_url(value);
204 } else if (!strcmp(name, "q")) { 210 } else if (!strcmp(name, "q")) {
205 cgit_query_search = xstrdup(value); 211 cgit_query_search = xstrdup(value);
206 } else if (!strcmp(name, "h")) { 212 } else if (!strcmp(name, "h")) {
207 cgit_query_head = xstrdup(value); 213 cgit_query_head = xstrdup(value);
208 cgit_query_has_symref = 1; 214 cgit_query_has_symref = 1;
209 } else if (!strcmp(name, "id")) { 215 } else if (!strcmp(name, "id")) {
210 cgit_query_sha1 = xstrdup(value); 216 cgit_query_sha1 = xstrdup(value);
211 cgit_query_has_sha1 = 1; 217 cgit_query_has_sha1 = 1;
212 } else if (!strcmp(name, "id2")) { 218 } else if (!strcmp(name, "id2")) {
213 cgit_query_sha2 = xstrdup(value); 219 cgit_query_sha2 = xstrdup(value);
214 cgit_query_has_sha1 = 1; 220 cgit_query_has_sha1 = 1;
215 } else if (!strcmp(name, "ofs")) { 221 } else if (!strcmp(name, "ofs")) {
216 cgit_query_ofs = atoi(value); 222 cgit_query_ofs = atoi(value);
217 } else if (!strcmp(name, "path")) { 223 } else if (!strcmp(name, "path")) {
218 cgit_query_path = xstrdup(value); 224 cgit_query_path = xstrdup(value);
219 } else if (!strcmp(name, "name")) { 225 } else if (!strcmp(name, "name")) {
220 cgit_query_name = xstrdup(value); 226 cgit_query_name = xstrdup(value);
221 } 227 }
222} 228}
223 229
224void *cgit_free_commitinfo(struct commitinfo *info) 230void *cgit_free_commitinfo(struct commitinfo *info)
225{ 231{
226 free(info->author); 232 free(info->author);
227 free(info->author_email); 233 free(info->author_email);
228 free(info->committer); 234 free(info->committer);
229 free(info->committer_email); 235 free(info->committer_email);
230 free(info->subject); 236 free(info->subject);
231 free(info); 237 free(info);
232 return NULL; 238 return NULL;
233} 239}
234 240
235int hextoint(char c) 241int hextoint(char c)
236{ 242{
237 if (c >= 'a' && c <= 'f') 243 if (c >= 'a' && c <= 'f')
238 return 10 + c - 'a'; 244 return 10 + c - 'a';
239 else if (c >= 'A' && c <= 'F') 245 else if (c >= 'A' && c <= 'F')
240 return 10 + c - 'A'; 246 return 10 + c - 'A';
241 else if (c >= '0' && c <= '9') 247 else if (c >= '0' && c <= '9')
242 return c - '0'; 248 return c - '0';
243 else 249 else
244 return -1; 250 return -1;
245} 251}
246 252
247void cgit_diff_tree_cb(struct diff_queue_struct *q, 253void cgit_diff_tree_cb(struct diff_queue_struct *q,
248 struct diff_options *options, void *data) 254 struct diff_options *options, void *data)
249{ 255{
250 int i; 256 int i;
251 257
252 for (i = 0; i < q->nr; i++) { 258 for (i = 0; i < q->nr; i++) {
253 if (q->queue[i]->status == 'U') 259 if (q->queue[i]->status == 'U')
254 continue; 260 continue;
255 ((filepair_fn)data)(q->queue[i]); 261 ((filepair_fn)data)(q->queue[i]);
256 } 262 }
257} 263}
258 264
259static int load_mmfile(mmfile_t *file, const unsigned char *sha1) 265static int load_mmfile(mmfile_t *file, const unsigned char *sha1)
260{ 266{
261 enum object_type type; 267 enum object_type type;
262 268
263 if (is_null_sha1(sha1)) { 269 if (is_null_sha1(sha1)) {
264 file->ptr = (char *)""; 270 file->ptr = (char *)"";
265 file->size = 0; 271 file->size = 0;
266 } else { 272 } else {
267 file->ptr = read_sha1_file(sha1, &type, &file->size); 273 file->ptr = read_sha1_file(sha1, &type, &file->size);
268 } 274 }
269 return 1; 275 return 1;
270} 276}
271 277
272/* 278/*
273 * Receive diff-buffers from xdiff and concatenate them as 279 * Receive diff-buffers from xdiff and concatenate them as
274 * needed across multiple callbacks. 280 * needed across multiple callbacks.
275 * 281 *
276 * This is basically a copy of xdiff-interface.c/xdiff_outf(), 282 * This is basically a copy of xdiff-interface.c/xdiff_outf(),
277 * ripped from git and modified to use globals instead of 283 * ripped from git and modified to use globals instead of
278 * a special callback-struct. 284 * a special callback-struct.
279 */ 285 */
280char *diffbuf = NULL; 286char *diffbuf = NULL;
281int buflen = 0; 287int buflen = 0;
282 288
283int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf) 289int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)
284{ 290{
285 int i; 291 int i;
286 292
287 for (i = 0; i < nbuf; i++) { 293 for (i = 0; i < nbuf; i++) {
288 if (mb[i].ptr[mb[i].size-1] != '\n') { 294 if (mb[i].ptr[mb[i].size-1] != '\n') {
289 /* Incomplete line */ 295 /* Incomplete line */
290 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 296 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
291 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 297 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
292 buflen += mb[i].size; 298 buflen += mb[i].size;
293 continue; 299 continue;
294 } 300 }
295 301
296 /* we have a complete line */ 302 /* we have a complete line */
297 if (!diffbuf) { 303 if (!diffbuf) {
298 ((linediff_fn)priv)(mb[i].ptr, mb[i].size); 304 ((linediff_fn)priv)(mb[i].ptr, mb[i].size);
299 continue; 305 continue;
300 } 306 }
301 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 307 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
302 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 308 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
303 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size); 309 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size);
304 free(diffbuf); 310 free(diffbuf);
305 diffbuf = NULL; 311 diffbuf = NULL;
306 buflen = 0; 312 buflen = 0;
307 } 313 }
308 if (diffbuf) { 314 if (diffbuf) {
309 ((linediff_fn)priv)(diffbuf, buflen); 315 ((linediff_fn)priv)(diffbuf, buflen);
310 free(diffbuf); 316 free(diffbuf);
311 diffbuf = NULL; 317 diffbuf = NULL;
312 buflen = 0; 318 buflen = 0;
313 } 319 }
314 return 0; 320 return 0;
315} 321}
316 322
317int cgit_diff_files(const unsigned char *old_sha1, 323int cgit_diff_files(const unsigned char *old_sha1,
318 const unsigned char *new_sha1, 324 const unsigned char *new_sha1,
319 linediff_fn fn) 325 linediff_fn fn)
320{ 326{
321 mmfile_t file1, file2; 327 mmfile_t file1, file2;
322 xpparam_t diff_params; 328 xpparam_t diff_params;
323 xdemitconf_t emit_params; 329 xdemitconf_t emit_params;
324 xdemitcb_t emit_cb; 330 xdemitcb_t emit_cb;
325 331
326 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1)) 332 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1))
327 return 1; 333 return 1;
328 334
329 diff_params.flags = XDF_NEED_MINIMAL; 335 diff_params.flags = XDF_NEED_MINIMAL;
330 emit_params.ctxlen = 3; 336 emit_params.ctxlen = 3;
331 emit_params.flags = XDL_EMIT_FUNCNAMES; 337 emit_params.flags = XDL_EMIT_FUNCNAMES;
332 emit_cb.outf = filediff_cb; 338 emit_cb.outf = filediff_cb;
333 emit_cb.priv = fn; 339 emit_cb.priv = fn;
334 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); 340 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb);
335 return 0; 341 return 0;
336} 342}
337 343
338void cgit_diff_tree(const unsigned char *old_sha1, 344void cgit_diff_tree(const unsigned char *old_sha1,
339 const unsigned char *new_sha1, 345 const unsigned char *new_sha1,
340 filepair_fn fn) 346 filepair_fn fn)
341{ 347{
342 struct diff_options opt; 348 struct diff_options opt;
343 int ret; 349 int ret;
344 350
345 diff_setup(&opt); 351 diff_setup(&opt);
346 opt.output_format = DIFF_FORMAT_CALLBACK; 352 opt.output_format = DIFF_FORMAT_CALLBACK;
347 opt.detect_rename = 1; 353 opt.detect_rename = 1;
348 opt.recursive = 1; 354 opt.recursive = 1;
349 opt.format_callback = cgit_diff_tree_cb; 355 opt.format_callback = cgit_diff_tree_cb;
350 opt.format_callback_data = fn; 356 opt.format_callback_data = fn;
351 diff_setup_done(&opt); 357 diff_setup_done(&opt);
352 358
353 if (old_sha1) 359 if (old_sha1)
354 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt); 360 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt);
355 else 361 else
356 ret = diff_root_tree_sha1(new_sha1, "", &opt); 362 ret = diff_root_tree_sha1(new_sha1, "", &opt);
357 diffcore_std(&opt); 363 diffcore_std(&opt);
358 diff_flush(&opt); 364 diff_flush(&opt);
359} 365}
360 366
361void cgit_diff_commit(struct commit *commit, filepair_fn fn) 367void cgit_diff_commit(struct commit *commit, filepair_fn fn)
362{ 368{
363 unsigned char *old_sha1 = NULL; 369 unsigned char *old_sha1 = NULL;
364 370
365 if (commit->parents) 371 if (commit->parents)
366 old_sha1 = commit->parents->item->object.sha1; 372 old_sha1 = commit->parents->item->object.sha1;
367 cgit_diff_tree(old_sha1, commit->object.sha1, fn); 373 cgit_diff_tree(old_sha1, commit->object.sha1, fn);
368} 374}
diff --git a/ui-summary.c b/ui-summary.c
index 5799773..5c1fc33 100644
--- a/ui-summary.c
+++ b/ui-summary.c
@@ -1,210 +1,212 @@
1/* ui-summary.c: functions for generating repo summary page 1/* ui-summary.c: functions for generating repo summary page
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 "cgit.h" 9#include "cgit.h"
10 10
11static int header; 11static int header;
12 12
13static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1, 13static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1,
14 int flags, void *cb_data) 14 int flags, void *cb_data)
15{ 15{
16 struct commit *commit; 16 struct commit *commit;
17 struct commitinfo *info; 17 struct commitinfo *info;
18 char buf[256], *url; 18 char buf[256], *url;
19 19
20 strncpy(buf, refname, sizeof(buf)); 20 strncpy(buf, refname, sizeof(buf));
21 commit = lookup_commit(sha1); 21 commit = lookup_commit(sha1);
22 if (commit && !parse_commit(commit)){ 22 if (commit && !parse_commit(commit)){
23 info = cgit_parse_commit(commit); 23 info = cgit_parse_commit(commit);
24 html("<tr><td>"); 24 html("<tr><td>");
25 url = cgit_pageurl(cgit_query_repo, "log", 25 url = cgit_pageurl(cgit_query_repo, "log",
26 fmt("h=%s", refname)); 26 fmt("h=%s", refname));
27 html_link_open(url, NULL, NULL); 27 html_link_open(url, NULL, NULL);
28 html_txt(buf); 28 html_txt(buf);
29 html_link_close(); 29 html_link_close();
30 html("</td><td>"); 30 html("</td><td>");
31 cgit_print_age(commit->date, -1, NULL); 31 cgit_print_age(commit->date, -1, NULL);
32 html("</td><td>"); 32 html("</td><td>");
33 html_txt(info->author); 33 html_txt(info->author);
34 html("</td><td>"); 34 html("</td><td>");
35 url = cgit_pageurl(cgit_query_repo, "commit", 35 url = cgit_pageurl(cgit_query_repo, "commit",
36 fmt("h=%s", sha1_to_hex(sha1))); 36 fmt("h=%s", sha1_to_hex(sha1)));
37 html_link_open(url, NULL, NULL); 37 html_link_open(url, NULL, NULL);
38 html_ntxt(cgit_max_msg_len, info->subject); 38 html_ntxt(cgit_max_msg_len, info->subject);
39 html_link_close(); 39 html_link_close();
40 html("</td></tr>\n"); 40 html("</td></tr>\n");
41 cgit_free_commitinfo(info); 41 cgit_free_commitinfo(info);
42 } else { 42 } else {
43 html("<tr><td>"); 43 html("<tr><td>");
44 html_txt(buf); 44 html_txt(buf);
45 html("</td><td colspan='3'>"); 45 html("</td><td colspan='3'>");
46 htmlf("*** bad ref %s ***", sha1_to_hex(sha1)); 46 htmlf("*** bad ref %s ***", sha1_to_hex(sha1));
47 html("</td></tr>\n"); 47 html("</td></tr>\n");
48 } 48 }
49 return 0; 49 return 0;
50} 50}
51 51
52 52
53static void cgit_print_object_ref(struct object *obj) 53static void cgit_print_object_ref(struct object *obj)
54{ 54{
55 char *page, *arg, *url; 55 char *page, *arg, *url;
56 56
57 if (obj->type == OBJ_COMMIT) { 57 if (obj->type == OBJ_COMMIT) {
58 page = "commit"; 58 page = "commit";
59 arg = "h"; 59 arg = "h";
60 } else if (obj->type == OBJ_TREE) { 60 } else if (obj->type == OBJ_TREE) {
61 page = "tree"; 61 page = "tree";
62 arg = "id"; 62 arg = "id";
63 } else { 63 } else {
64 page = "view"; 64 page = "view";
65 arg = "id"; 65 arg = "id";
66 } 66 }
67 67
68 url = cgit_pageurl(cgit_query_repo, page, 68 url = cgit_pageurl(cgit_query_repo, page,
69 fmt("%s=%s", arg, sha1_to_hex(obj->sha1))); 69 fmt("%s=%s", arg, sha1_to_hex(obj->sha1)));
70 html_link_open(url, NULL, NULL); 70 html_link_open(url, NULL, NULL);
71 htmlf("%s %s", typename(obj->type), 71 htmlf("%s %s", typename(obj->type),
72 sha1_to_hex(obj->sha1)); 72 sha1_to_hex(obj->sha1));
73 html_link_close(); 73 html_link_close();
74} 74}
75 75
76static void print_tag_header() 76static void print_tag_header()
77{ 77{
78 html("<tr class='nohover'><th class='left'>Tag</th>" 78 html("<tr class='nohover'><th class='left'>Tag</th>"
79 "<th class='left'>Age</th>" 79 "<th class='left'>Age</th>"
80 "<th class='left'>Author</th>" 80 "<th class='left'>Author</th>"
81 "<th class='left'>Reference</th></tr>\n"); 81 "<th class='left'>Reference</th></tr>\n");
82 header = 1; 82 header = 1;
83} 83}
84 84
85static int cgit_print_tag_cb(const char *refname, const unsigned char *sha1, 85static int cgit_print_tag_cb(const char *refname, const unsigned char *sha1,
86 int flags, void *cb_data) 86 int flags, void *cb_data)
87{ 87{
88 struct tag *tag; 88 struct tag *tag;
89 struct taginfo *info; 89 struct taginfo *info;
90 struct object *obj; 90 struct object *obj;
91 char buf[256], *url; 91 char buf[256], *url;
92 92
93 strncpy(buf, refname, sizeof(buf)); 93 strncpy(buf, refname, sizeof(buf));
94 obj = parse_object(sha1); 94 obj = parse_object(sha1);
95 if (!obj) 95 if (!obj)
96 return 1; 96 return 1;
97 if (obj->type == OBJ_TAG) { 97 if (obj->type == OBJ_TAG) {
98 tag = lookup_tag(sha1); 98 tag = lookup_tag(sha1);
99 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 99 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
100 return 2; 100 return 2;
101 if (!header) 101 if (!header)
102 print_tag_header(); 102 print_tag_header();
103 html("<tr><td>"); 103 html("<tr><td>");
104 url = cgit_pageurl(cgit_query_repo, "view", 104 url = cgit_pageurl(cgit_query_repo, "view",
105 fmt("id=%s", sha1_to_hex(sha1))); 105 fmt("id=%s", sha1_to_hex(sha1)));
106 html_link_open(url, NULL, NULL); 106 html_link_open(url, NULL, NULL);
107 html_txt(buf); 107 html_txt(buf);
108 html_link_close(); 108 html_link_close();
109 html("</td><td>"); 109 html("</td><td>");
110 if (info->tagger_date > 0) 110 if (info->tagger_date > 0)
111 cgit_print_age(info->tagger_date, -1, NULL); 111 cgit_print_age(info->tagger_date, -1, NULL);
112 html("</td><td>"); 112 html("</td><td>");
113 if (info->tagger) 113 if (info->tagger)
114 html(info->tagger); 114 html(info->tagger);
115 html("</td><td>"); 115 html("</td><td>");
116 cgit_print_object_ref(tag->tagged); 116 cgit_print_object_ref(tag->tagged);
117 html("</td></tr>\n"); 117 html("</td></tr>\n");
118 } else { 118 } else {
119 if (!header) 119 if (!header)
120 print_tag_header(); 120 print_tag_header();
121 html("<tr><td>"); 121 html("<tr><td>");
122 html_txt(buf); 122 html_txt(buf);
123 html("</td><td colspan='2'/><td>"); 123 html("</td><td colspan='2'/><td>");
124 cgit_print_object_ref(obj); 124 cgit_print_object_ref(obj);
125 html("</td></tr>\n"); 125 html("</td></tr>\n");
126 } 126 }
127 return 0; 127 return 0;
128} 128}
129 129
130static int cgit_print_archive_cb(const char *refname, const unsigned char *sha1, 130static int cgit_print_archive_cb(const char *refname, const unsigned char *sha1,
131 int flags, void *cb_data) 131 int flags, void *cb_data)
132{ 132{
133 struct tag *tag; 133 struct tag *tag;
134 struct taginfo *info; 134 struct taginfo *info;
135 struct object *obj; 135 struct object *obj;
136 char buf[256], *url; 136 char buf[256], *url;
137 unsigned char fileid[20]; 137 unsigned char fileid[20];
138 138
139 if (prefixcmp(refname, "refs/archives")) 139 if (prefixcmp(refname, "refs/archives"))
140 return 0; 140 return 0;
141 strncpy(buf, refname+14, sizeof(buf)); 141 strncpy(buf, refname+14, sizeof(buf));
142 obj = parse_object(sha1); 142 obj = parse_object(sha1);
143 if (!obj) 143 if (!obj)
144 return 1; 144 return 1;
145 if (obj->type == OBJ_TAG) { 145 if (obj->type == OBJ_TAG) {
146 tag = lookup_tag(sha1); 146 tag = lookup_tag(sha1);
147 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 147 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
148 return 0; 148 return 0;
149 hashcpy(fileid, tag->tagged->sha1); 149 hashcpy(fileid, tag->tagged->sha1);
150 } else if (obj->type != OBJ_BLOB) { 150 } else if (obj->type != OBJ_BLOB) {
151 return 0; 151 return 0;
152 } else { 152 } else {
153 hashcpy(fileid, sha1); 153 hashcpy(fileid, sha1);
154 } 154 }
155 if (!header) { 155 if (!header) {
156 html("<table>"); 156 html("<table id='downloads'>");
157 html("<tr><th>Downloads</th></tr>"); 157 html("<tr><th>Downloads</th></tr>");
158 header = 1; 158 header = 1;
159 } 159 }
160 html("<tr><td>"); 160 html("<tr><td>");
161 url = cgit_pageurl(cgit_query_repo, "blob", 161 url = cgit_pageurl(cgit_query_repo, "blob",
162 fmt("id=%s&path=%s", sha1_to_hex(fileid), 162 fmt("id=%s&path=%s", sha1_to_hex(fileid),
163 buf)); 163 buf));
164 html_link_open(url, NULL, NULL); 164 html_link_open(url, NULL, NULL);
165 html_txt(buf); 165 html_txt(buf);
166 html_link_close(); 166 html_link_close();
167 html("</td><tr>"); 167 html("</td><tr>");
168 return 0; 168 return 0;
169} 169}
170 170
171static void cgit_print_branches() 171static void cgit_print_branches()
172{ 172{
173 html("<tr class='nohover'><th class='left'>Branch</th>" 173 html("<tr class='nohover'><th class='left'>Branch</th>"
174 "<th class='left'>Idle</th>" 174 "<th class='left'>Idle</th>"
175 "<th class='left'>Author</th>" 175 "<th class='left'>Author</th>"
176 "<th class='left'>Head commit</th></tr>\n"); 176 "<th class='left'>Head commit</th></tr>\n");
177 for_each_branch_ref(cgit_print_branch_cb, NULL); 177 for_each_branch_ref(cgit_print_branch_cb, NULL);
178} 178}
179 179
180static void cgit_print_tags() 180static void cgit_print_tags()
181{ 181{
182 header = 0; 182 header = 0;
183 for_each_tag_ref(cgit_print_tag_cb, NULL); 183 for_each_tag_ref(cgit_print_tag_cb, NULL);
184} 184}
185 185
186static void cgit_print_archives() 186static void cgit_print_archives()
187{ 187{
188 header = 0; 188 header = 0;
189 for_each_ref(cgit_print_archive_cb, NULL); 189 for_each_ref(cgit_print_archive_cb, NULL);
190 if (header) 190 if (header)
191 html("</table>"); 191 html("</table>");
192} 192}
193 193
194void cgit_print_summary() 194void cgit_print_summary()
195{ 195{
196 html("<table class='list nowrap'>"); 196 html("<div id='summary'>");
197 html("<tr class='nohover'><td id='summary' colspan='3'>"); 197 cgit_print_archives();
198 html("<h2>"); 198 html("<h2>");
199 html_txt(cgit_repo->name); 199 html_txt(cgit_repo->name);
200 html(" - "); 200 html(" - ");
201 html_txt(cgit_repo->desc); 201 html_txt(cgit_repo->desc);
202 html("</h2>"); 202 html("</h2>");
203 html("</td><td id='archivelist'>"); 203 if (cgit_repo->readme)
204 cgit_print_archives(); 204 html_include(cgit_repo->readme);
205 html("</td></tr>"); 205 html("</div>");
206
207 html("<table class='list nowrap'>");
206 cgit_print_branches(); 208 cgit_print_branches();
207 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>"); 209 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>");
208 cgit_print_tags(); 210 cgit_print_tags();
209 html("</table>"); 211 html("</table>");
210} 212}