summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.css8
-rw-r--r--ui-shared.c6
2 files changed, 14 insertions, 0 deletions
diff --git a/cgit.css b/cgit.css
index 0cb894a..563f8e1 100644
--- a/cgit.css
+++ b/cgit.css
@@ -1,488 +1,496 @@
1body, table, form { 1body, table, form {
2 padding: 0em; 2 padding: 0em;
3 margin: 0em; 3 margin: 0em;
4} 4}
5 5
6body { 6body {
7 font-family: sans-serif; 7 font-family: sans-serif;
8 font-size: 10pt; 8 font-size: 10pt;
9 color: #333; 9 color: #333;
10 background: white; 10 background: white;
11 padding: 4px; 11 padding: 4px;
12} 12}
13 13
14a { 14a {
15 color: blue; 15 color: blue;
16 text-decoration: none; 16 text-decoration: none;
17} 17}
18 18
19a:hover { 19a:hover {
20 text-decoration: underline; 20 text-decoration: underline;
21} 21}
22 22
23table { 23table {
24 border-collapse: collapse; 24 border-collapse: collapse;
25} 25}
26 26
27table#header { 27table#header {
28 width: 100%; 28 width: 100%;
29 margin-bottom: 1em; 29 margin-bottom: 1em;
30} 30}
31 31
32table#header td.logo { 32table#header td.logo {
33 width: 96px; 33 width: 96px;
34} 34}
35 35
36table#header td.main { 36table#header td.main {
37 font-size: 250%; 37 font-size: 250%;
38 padding-left: 10px; 38 padding-left: 10px;
39 white-space: nowrap; 39 white-space: nowrap;
40} 40}
41 41
42table#header td.main a { 42table#header td.main a {
43 color: #000; 43 color: #000;
44} 44}
45 45
46table#header td.form { 46table#header td.form {
47 text-align: right; 47 text-align: right;
48 vertical-align: bottom; 48 vertical-align: bottom;
49 padding-right: 1em; 49 padding-right: 1em;
50 padding-bottom: 2px; 50 padding-bottom: 2px;
51 white-space: nowrap; 51 white-space: nowrap;
52} 52}
53 53
54table#header td.form form, 54table#header td.form form,
55table#header td.form input, 55table#header td.form input,
56table#header td.form select { 56table#header td.form select {
57 font-size: 90%; 57 font-size: 90%;
58} 58}
59 59
60table#header td.sub { 60table#header td.sub {
61 color: #777; 61 color: #777;
62 border-top: solid 1px #ccc; 62 border-top: solid 1px #ccc;
63 padding-left: 10px; 63 padding-left: 10px;
64} 64}
65 65
66table.tabs { 66table.tabs {
67 /* border-bottom: solid 2px #ccc; */ 67 /* border-bottom: solid 2px #ccc; */
68 border-collapse: collapse; 68 border-collapse: collapse;
69 margin-top: 2em; 69 margin-top: 2em;
70 margin-bottom: 0px; 70 margin-bottom: 0px;
71 width: 100%; 71 width: 100%;
72} 72}
73 73
74table.tabs td { 74table.tabs td {
75 padding: 0px 1em; 75 padding: 0px 1em;
76 vertical-align: bottom; 76 vertical-align: bottom;
77} 77}
78 78
79table.tabs td a { 79table.tabs td a {
80 padding: 2px 0.75em; 80 padding: 2px 0.75em;
81 color: #777; 81 color: #777;
82 font-size: 110%; 82 font-size: 110%;
83} 83}
84 84
85table.tabs td a.active { 85table.tabs td a.active {
86 color: #000; 86 color: #000;
87 background-color: #ccc; 87 background-color: #ccc;
88} 88}
89 89
90table.tabs td.form { 90table.tabs td.form {
91 text-align: right; 91 text-align: right;
92} 92}
93 93
94table.tabs td.form form { 94table.tabs td.form form {
95 padding-bottom: 2px; 95 padding-bottom: 2px;
96 font-size: 90%; 96 font-size: 90%;
97 white-space: nowrap; 97 white-space: nowrap;
98} 98}
99 99
100table.tabs td.form input, 100table.tabs td.form input,
101table.tabs td.form select { 101table.tabs td.form select {
102 font-size: 90%; 102 font-size: 90%;
103} 103}
104 104
105div.path {
106 margin: 0px;
107 padding: 5px 2em 2px 2em;
108 color: #000;
109 background-color: #ccc;
110 font-weight: bold;
111}
112
105div.content { 113div.content {
106 margin: 0px; 114 margin: 0px;
107 padding: 2em; 115 padding: 2em;
108 border-top: solid 3px #ccc; 116 border-top: solid 3px #ccc;
109 border-bottom: solid 3px #ccc; 117 border-bottom: solid 3px #ccc;
110} 118}
111 119
112 120
113table.list { 121table.list {
114 width: 100%; 122 width: 100%;
115 border: none; 123 border: none;
116 border-collapse: collapse; 124 border-collapse: collapse;
117} 125}
118 126
119table.list tr { 127table.list tr {
120 background: white; 128 background: white;
121} 129}
122 130
123table.list tr.logheader { 131table.list tr.logheader {
124 background: #eee; 132 background: #eee;
125} 133}
126 134
127table.list tr:hover { 135table.list tr:hover {
128 background: #eee; 136 background: #eee;
129} 137}
130 138
131table.list tr.nohover:hover { 139table.list tr.nohover:hover {
132 background: white; 140 background: white;
133} 141}
134 142
135table.list th { 143table.list th {
136 font-weight: bold; 144 font-weight: bold;
137 /* color: #888; 145 /* color: #888;
138 border-top: dashed 1px #888; 146 border-top: dashed 1px #888;
139 border-bottom: dashed 1px #888; 147 border-bottom: dashed 1px #888;
140 */ 148 */
141 padding: 0.1em 0.5em 0.05em 0.5em; 149 padding: 0.1em 0.5em 0.05em 0.5em;
142 vertical-align: baseline; 150 vertical-align: baseline;
143} 151}
144 152
145table.list td { 153table.list td {
146 border: none; 154 border: none;
147 padding: 0.1em 0.5em 0.1em 0.5em; 155 padding: 0.1em 0.5em 0.1em 0.5em;
148} 156}
149 157
150table.list td.logsubject { 158table.list td.logsubject {
151 font-family: monospace; 159 font-family: monospace;
152 font-weight: bold; 160 font-weight: bold;
153} 161}
154 162
155table.list td.logmsg { 163table.list td.logmsg {
156 font-family: monospace; 164 font-family: monospace;
157 white-space: pre; 165 white-space: pre;
158 padding: 1em 0.5em 2em 0.5em; 166 padding: 1em 0.5em 2em 0.5em;
159} 167}
160 168
161table.list td a { 169table.list td a {
162 color: black; 170 color: black;
163} 171}
164 172
165table.list td a.ls-dir { 173table.list td a.ls-dir {
166 font-weight: bold; 174 font-weight: bold;
167 color: #00f; 175 color: #00f;
168} 176}
169 177
170table.list td a:hover { 178table.list td a:hover {
171 color: #00f; 179 color: #00f;
172} 180}
173 181
174img { 182img {
175 border: none; 183 border: none;
176} 184}
177 185
178input#switch-btn { 186input#switch-btn {
179 margin: 2px 0px 0px 0px; 187 margin: 2px 0px 0px 0px;
180} 188}
181 189
182td#sidebar input.txt { 190td#sidebar input.txt {
183 width: 100%; 191 width: 100%;
184 margin: 2px 0px 0px 0px; 192 margin: 2px 0px 0px 0px;
185} 193}
186 194
187table#grid { 195table#grid {
188 margin: 0px; 196 margin: 0px;
189} 197}
190 198
191td#content { 199td#content {
192 vertical-align: top; 200 vertical-align: top;
193 padding: 1em 2em 1em 1em; 201 padding: 1em 2em 1em 1em;
194 border: none; 202 border: none;
195} 203}
196 204
197div#summary { 205div#summary {
198 vertical-align: top; 206 vertical-align: top;
199 margin-bottom: 1em; 207 margin-bottom: 1em;
200} 208}
201 209
202table#downloads { 210table#downloads {
203 float: right; 211 float: right;
204 border-collapse: collapse; 212 border-collapse: collapse;
205 border: solid 1px #777; 213 border: solid 1px #777;
206 margin-left: 0.5em; 214 margin-left: 0.5em;
207 margin-bottom: 0.5em; 215 margin-bottom: 0.5em;
208} 216}
209 217
210table#downloads th { 218table#downloads th {
211 background-color: #ccc; 219 background-color: #ccc;
212} 220}
213 221
214div#blob { 222div#blob {
215 border: solid 1px black; 223 border: solid 1px black;
216} 224}
217 225
218div.error { 226div.error {
219 color: red; 227 color: red;
220 font-weight: bold; 228 font-weight: bold;
221 margin: 1em 2em; 229 margin: 1em 2em;
222} 230}
223 231
224a.ls-blob, a.ls-dir, a.ls-mod { 232a.ls-blob, a.ls-dir, a.ls-mod {
225 font-family: monospace; 233 font-family: monospace;
226} 234}
227 235
228td.ls-size { 236td.ls-size {
229 text-align: right; 237 text-align: right;
230 font-family: monospace; 238 font-family: monospace;
231 width: 10em; 239 width: 10em;
232} 240}
233 241
234td.ls-mode { 242td.ls-mode {
235 font-family: monospace; 243 font-family: monospace;
236 width: 10em; 244 width: 10em;
237} 245}
238 246
239table.blob { 247table.blob {
240 margin-top: 0.5em; 248 margin-top: 0.5em;
241 border-top: solid 1px black; 249 border-top: solid 1px black;
242} 250}
243 251
244table.blob td.lines { 252table.blob td.lines {
245 margin: 0; padding: 0 0 0 0.5em; 253 margin: 0; padding: 0 0 0 0.5em;
246 vertical-align: top; 254 vertical-align: top;
247 color: black; 255 color: black;
248} 256}
249 257
250table.blob td.linenumbers { 258table.blob td.linenumbers {
251 margin: 0; padding: 0 0.5em 0 0.5em; 259 margin: 0; padding: 0 0.5em 0 0.5em;
252 vertical-align: top; 260 vertical-align: top;
253 text-align: right; 261 text-align: right;
254 border-right: 1px solid gray; 262 border-right: 1px solid gray;
255} 263}
256 264
257table.blob pre { 265table.blob pre {
258 padding: 0; margin: 0; 266 padding: 0; margin: 0;
259} 267}
260 268
261table.blob a.no { 269table.blob a.no {
262 color: gray; 270 color: gray;
263 text-align: right; 271 text-align: right;
264 text-decoration: none; 272 text-decoration: none;
265} 273}
266 274
267table.blob a.no a:hover { 275table.blob a.no a:hover {
268 color: black; 276 color: black;
269} 277}
270 278
271table.bin-blob { 279table.bin-blob {
272 margin-top: 0.5em; 280 margin-top: 0.5em;
273 border: solid 1px black; 281 border: solid 1px black;
274} 282}
275 283
276table.bin-blob th { 284table.bin-blob th {
277 font-family: monospace; 285 font-family: monospace;
278 white-space: pre; 286 white-space: pre;
279 border: solid 1px #777; 287 border: solid 1px #777;
280 padding: 0.5em 1em; 288 padding: 0.5em 1em;
281} 289}
282 290
283table.bin-blob td { 291table.bin-blob td {
284 font-family: monospace; 292 font-family: monospace;
285 white-space: pre; 293 white-space: pre;
286 border-left: solid 1px #777; 294 border-left: solid 1px #777;
287 padding: 0em 1em; 295 padding: 0em 1em;
288} 296}
289 297
290table.nowrap td { 298table.nowrap td {
291 white-space: nowrap; 299 white-space: nowrap;
292} 300}
293 301
294table.commit-info { 302table.commit-info {
295 border-collapse: collapse; 303 border-collapse: collapse;
296 margin-top: 1.5em; 304 margin-top: 1.5em;
297} 305}
298 306
299table.commit-info th { 307table.commit-info th {
300 text-align: left; 308 text-align: left;
301 font-weight: normal; 309 font-weight: normal;
302 padding: 0.1em 1em 0.1em 0.1em; 310 padding: 0.1em 1em 0.1em 0.1em;
303 vertical-align: top; 311 vertical-align: top;
304} 312}
305 313
306table.commit-info td { 314table.commit-info td {
307 font-weight: normal; 315 font-weight: normal;
308 padding: 0.1em 1em 0.1em 0.1em; 316 padding: 0.1em 1em 0.1em 0.1em;
309} 317}
310 318
311div.commit-subject { 319div.commit-subject {
312 font-weight: bold; 320 font-weight: bold;
313 font-size: 125%; 321 font-size: 125%;
314 margin: 1.5em 0em 0.5em 0em; 322 margin: 1.5em 0em 0.5em 0em;
315 padding: 0em; 323 padding: 0em;
316} 324}
317 325
318div.commit-msg { 326div.commit-msg {
319 white-space: pre; 327 white-space: pre;
320 font-family: monospace; 328 font-family: monospace;
321} 329}
322 330
323div.diffstat-header { 331div.diffstat-header {
324 font-weight: bold; 332 font-weight: bold;
325 padding-top: 1.5em; 333 padding-top: 1.5em;
326} 334}
327 335
328table.diffstat { 336table.diffstat {
329 border-collapse: collapse; 337 border-collapse: collapse;
330 border: solid 1px #aaa; 338 border: solid 1px #aaa;
331 background-color: #eee; 339 background-color: #eee;
332} 340}
333 341
334table.diffstat th { 342table.diffstat th {
335 font-weight: normal; 343 font-weight: normal;
336 text-align: left; 344 text-align: left;
337 text-decoration: underline; 345 text-decoration: underline;
338 padding: 0.1em 1em 0.1em 0.1em; 346 padding: 0.1em 1em 0.1em 0.1em;
339 font-size: 100%; 347 font-size: 100%;
340} 348}
341 349
342table.diffstat td { 350table.diffstat td {
343 padding: 0.2em 0.2em 0.1em 0.1em; 351 padding: 0.2em 0.2em 0.1em 0.1em;
344 font-size: 100%; 352 font-size: 100%;
345 border: none; 353 border: none;
346} 354}
347 355
348table.diffstat td.mode { 356table.diffstat td.mode {
349 white-space: nowrap; 357 white-space: nowrap;
350} 358}
351 359
352table.diffstat td span.modechange { 360table.diffstat td span.modechange {
353 padding-left: 1em; 361 padding-left: 1em;
354 color: red; 362 color: red;
355} 363}
356 364
357table.diffstat td.add a { 365table.diffstat td.add a {
358 color: green; 366 color: green;
359} 367}
360 368
361table.diffstat td.del a { 369table.diffstat td.del a {
362 color: red; 370 color: red;
363} 371}
364 372
365table.diffstat td.upd a { 373table.diffstat td.upd a {
366 color: blue; 374 color: blue;
367} 375}
368 376
369table.diffstat td.graph { 377table.diffstat td.graph {
370 width: 500px; 378 width: 500px;
371 vertical-align: middle; 379 vertical-align: middle;
372} 380}
373 381
374table.diffstat td.graph table { 382table.diffstat td.graph table {
375 border: none; 383 border: none;
376} 384}
377 385
378table.diffstat td.graph td { 386table.diffstat td.graph td {
379 padding: 0px; 387 padding: 0px;
380 border: 0px; 388 border: 0px;
381 height: 7pt; 389 height: 7pt;
382} 390}
383 391
384table.diffstat td.graph td.add { 392table.diffstat td.graph td.add {
385 background-color: #5c5; 393 background-color: #5c5;
386} 394}
387 395
388table.diffstat td.graph td.rem { 396table.diffstat td.graph td.rem {
389 background-color: #c55; 397 background-color: #c55;
390} 398}
391 399
392div.diffstat-summary { 400div.diffstat-summary {
393 color: #888; 401 color: #888;
394 padding-top: 0.5em; 402 padding-top: 0.5em;
395} 403}
396 404
397table.diff { 405table.diff {
398 width: 100%; 406 width: 100%;
399} 407}
400 408
401table.diff td { 409table.diff td {
402 font-family: monospace; 410 font-family: monospace;
403 white-space: pre; 411 white-space: pre;
404} 412}
405 413
406table.diff td div.head { 414table.diff td div.head {
407 font-weight: bold; 415 font-weight: bold;
408 margin-top: 1em; 416 margin-top: 1em;
409 color: black; 417 color: black;
410} 418}
411 419
412table.diff td div.hunk { 420table.diff td div.hunk {
413 color: #009; 421 color: #009;
414} 422}
415 423
416table.diff td div.add { 424table.diff td div.add {
417 color: green; 425 color: green;
418} 426}
419 427
420table.diff td div.del { 428table.diff td div.del {
421 color: red; 429 color: red;
422} 430}
423 431
424.sha1 { 432.sha1 {
425 font-family: monospace; 433 font-family: monospace;
426 font-size: 90%; 434 font-size: 90%;
427} 435}
428 436
429.left { 437.left {
430 text-align: left; 438 text-align: left;
431} 439}
432 440
433.right { 441.right {
434 text-align: right; 442 text-align: right;
435} 443}
436 444
437table.list td.reposection { 445table.list td.reposection {
438 font-style: italic; 446 font-style: italic;
439 color: #888; 447 color: #888;
440} 448}
441 449
442a.button { 450a.button {
443 font-size: 80%; 451 font-size: 80%;
444 padding: 0em 0.5em; 452 padding: 0em 0.5em;
445} 453}
446 454
447a.primary { 455a.primary {
448 font-size: 100%; 456 font-size: 100%;
449} 457}
450 458
451a.secondary { 459a.secondary {
452 font-size: 90%; 460 font-size: 90%;
453} 461}
454 462
455td.toplevel-repo { 463td.toplevel-repo {
456 464
457} 465}
458 466
459table.list td.sublevel-repo { 467table.list td.sublevel-repo {
460 padding-left: 1.5em; 468 padding-left: 1.5em;
461} 469}
462 470
463div.pager { 471div.pager {
464 text-align: center; 472 text-align: center;
465 margin: 1em 0em 0em 0em; 473 margin: 1em 0em 0em 0em;
466} 474}
467 475
468div.pager a { 476div.pager a {
469 color: #777; 477 color: #777;
470 margin: 0em 0.5em; 478 margin: 0em 0.5em;
471} 479}
472 480
473span.age-mins { 481span.age-mins {
474 font-weight: bold; 482 font-weight: bold;
475 color: #080; 483 color: #080;
476} 484}
477 485
478span.age-hours { 486span.age-hours {
479 color: #080; 487 color: #080;
480} 488}
481 489
482span.age-days { 490span.age-days {
483 color: #040; 491 color: #040;
484} 492}
485 493
486span.age-weeks { 494span.age-weeks {
487 color: #444; 495 color: #444;
488} 496}
diff --git a/ui-shared.c b/ui-shared.c
index 3d5030b..bc14e70 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -376,422 +376,428 @@ void cgit_diff_link(const char *name, const char *title, const char *class,
376 html(delim); 376 html(delim);
377 html("id2="); 377 html("id2=");
378 html_url_arg(old_rev); 378 html_url_arg(old_rev);
379 delim = "&"; 379 delim = "&";
380 } 380 }
381 if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) { 381 if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) {
382 html(delim); 382 html(delim);
383 html("ss=1"); 383 html("ss=1");
384 } 384 }
385 html("'>"); 385 html("'>");
386 html_txt(name); 386 html_txt(name);
387 html("</a>"); 387 html("</a>");
388} 388}
389 389
390void cgit_patch_link(const char *name, const char *title, const char *class, 390void cgit_patch_link(const char *name, const char *title, const char *class,
391 const char *head, const char *rev) 391 const char *head, const char *rev)
392{ 392{
393 reporevlink("patch", name, title, class, head, rev, NULL); 393 reporevlink("patch", name, title, class, head, rev, NULL);
394} 394}
395 395
396void cgit_stats_link(const char *name, const char *title, const char *class, 396void cgit_stats_link(const char *name, const char *title, const char *class,
397 const char *head, const char *path) 397 const char *head, const char *path)
398{ 398{
399 reporevlink("stats", name, title, class, head, NULL, path); 399 reporevlink("stats", name, title, class, head, NULL, path);
400} 400}
401 401
402void cgit_object_link(struct object *obj) 402void cgit_object_link(struct object *obj)
403{ 403{
404 char *page, *shortrev, *fullrev, *name; 404 char *page, *shortrev, *fullrev, *name;
405 405
406 fullrev = sha1_to_hex(obj->sha1); 406 fullrev = sha1_to_hex(obj->sha1);
407 shortrev = xstrdup(fullrev); 407 shortrev = xstrdup(fullrev);
408 shortrev[10] = '\0'; 408 shortrev[10] = '\0';
409 if (obj->type == OBJ_COMMIT) { 409 if (obj->type == OBJ_COMMIT) {
410 cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, 410 cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL,
411 ctx.qry.head, fullrev, 0); 411 ctx.qry.head, fullrev, 0);
412 return; 412 return;
413 } else if (obj->type == OBJ_TREE) 413 } else if (obj->type == OBJ_TREE)
414 page = "tree"; 414 page = "tree";
415 else if (obj->type == OBJ_TAG) 415 else if (obj->type == OBJ_TAG)
416 page = "tag"; 416 page = "tag";
417 else 417 else
418 page = "blob"; 418 page = "blob";
419 name = fmt("%s %s...", typename(obj->type), shortrev); 419 name = fmt("%s %s...", typename(obj->type), shortrev);
420 reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL); 420 reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL);
421} 421}
422 422
423void cgit_print_date(time_t secs, const char *format, int local_time) 423void cgit_print_date(time_t secs, const char *format, int local_time)
424{ 424{
425 char buf[64]; 425 char buf[64];
426 struct tm *time; 426 struct tm *time;
427 427
428 if (!secs) 428 if (!secs)
429 return; 429 return;
430 if(local_time) 430 if(local_time)
431 time = localtime(&secs); 431 time = localtime(&secs);
432 else 432 else
433 time = gmtime(&secs); 433 time = gmtime(&secs);
434 strftime(buf, sizeof(buf)-1, format, time); 434 strftime(buf, sizeof(buf)-1, format, time);
435 html_txt(buf); 435 html_txt(buf);
436} 436}
437 437
438void cgit_print_age(time_t t, time_t max_relative, const char *format) 438void cgit_print_age(time_t t, time_t max_relative, const char *format)
439{ 439{
440 time_t now, secs; 440 time_t now, secs;
441 441
442 if (!t) 442 if (!t)
443 return; 443 return;
444 time(&now); 444 time(&now);
445 secs = now - t; 445 secs = now - t;
446 446
447 if (secs > max_relative && max_relative >= 0) { 447 if (secs > max_relative && max_relative >= 0) {
448 cgit_print_date(t, format, ctx.cfg.local_time); 448 cgit_print_date(t, format, ctx.cfg.local_time);
449 return; 449 return;
450 } 450 }
451 451
452 if (secs < TM_HOUR * 2) { 452 if (secs < TM_HOUR * 2) {
453 htmlf("<span class='age-mins'>%.0f min.</span>", 453 htmlf("<span class='age-mins'>%.0f min.</span>",
454 secs * 1.0 / TM_MIN); 454 secs * 1.0 / TM_MIN);
455 return; 455 return;
456 } 456 }
457 if (secs < TM_DAY * 2) { 457 if (secs < TM_DAY * 2) {
458 htmlf("<span class='age-hours'>%.0f hours</span>", 458 htmlf("<span class='age-hours'>%.0f hours</span>",
459 secs * 1.0 / TM_HOUR); 459 secs * 1.0 / TM_HOUR);
460 return; 460 return;
461 } 461 }
462 if (secs < TM_WEEK * 2) { 462 if (secs < TM_WEEK * 2) {
463 htmlf("<span class='age-days'>%.0f days</span>", 463 htmlf("<span class='age-days'>%.0f days</span>",
464 secs * 1.0 / TM_DAY); 464 secs * 1.0 / TM_DAY);
465 return; 465 return;
466 } 466 }
467 if (secs < TM_MONTH * 2) { 467 if (secs < TM_MONTH * 2) {
468 htmlf("<span class='age-weeks'>%.0f weeks</span>", 468 htmlf("<span class='age-weeks'>%.0f weeks</span>",
469 secs * 1.0 / TM_WEEK); 469 secs * 1.0 / TM_WEEK);
470 return; 470 return;
471 } 471 }
472 if (secs < TM_YEAR * 2) { 472 if (secs < TM_YEAR * 2) {
473 htmlf("<span class='age-months'>%.0f months</span>", 473 htmlf("<span class='age-months'>%.0f months</span>",
474 secs * 1.0 / TM_MONTH); 474 secs * 1.0 / TM_MONTH);
475 return; 475 return;
476 } 476 }
477 htmlf("<span class='age-years'>%.0f years</span>", 477 htmlf("<span class='age-years'>%.0f years</span>",
478 secs * 1.0 / TM_YEAR); 478 secs * 1.0 / TM_YEAR);
479} 479}
480 480
481void cgit_print_http_headers(struct cgit_context *ctx) 481void cgit_print_http_headers(struct cgit_context *ctx)
482{ 482{
483 if (ctx->env.no_http && !strcmp(ctx->env.no_http, "1")) 483 if (ctx->env.no_http && !strcmp(ctx->env.no_http, "1"))
484 return; 484 return;
485 485
486 if (ctx->page.status) 486 if (ctx->page.status)
487 htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg); 487 htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg);
488 if (ctx->page.mimetype && ctx->page.charset) 488 if (ctx->page.mimetype && ctx->page.charset)
489 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype, 489 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype,
490 ctx->page.charset); 490 ctx->page.charset);
491 else if (ctx->page.mimetype) 491 else if (ctx->page.mimetype)
492 htmlf("Content-Type: %s\n", ctx->page.mimetype); 492 htmlf("Content-Type: %s\n", ctx->page.mimetype);
493 if (ctx->page.size) 493 if (ctx->page.size)
494 htmlf("Content-Length: %ld\n", ctx->page.size); 494 htmlf("Content-Length: %ld\n", ctx->page.size);
495 if (ctx->page.filename) 495 if (ctx->page.filename)
496 htmlf("Content-Disposition: inline; filename=\"%s\"\n", 496 htmlf("Content-Disposition: inline; filename=\"%s\"\n",
497 ctx->page.filename); 497 ctx->page.filename);
498 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified)); 498 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified));
499 htmlf("Expires: %s\n", http_date(ctx->page.expires)); 499 htmlf("Expires: %s\n", http_date(ctx->page.expires));
500 if (ctx->page.etag) 500 if (ctx->page.etag)
501 htmlf("ETag: \"%s\"\n", ctx->page.etag); 501 htmlf("ETag: \"%s\"\n", ctx->page.etag);
502 html("\n"); 502 html("\n");
503 if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD")) 503 if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD"))
504 exit(0); 504 exit(0);
505} 505}
506 506
507void cgit_print_docstart(struct cgit_context *ctx) 507void cgit_print_docstart(struct cgit_context *ctx)
508{ 508{
509 if (ctx->cfg.embedded) { 509 if (ctx->cfg.embedded) {
510 if (ctx->cfg.header) 510 if (ctx->cfg.header)
511 html_include(ctx->cfg.header); 511 html_include(ctx->cfg.header);
512 return; 512 return;
513 } 513 }
514 514
515 char *host = cgit_hosturl(); 515 char *host = cgit_hosturl();
516 html(cgit_doctype); 516 html(cgit_doctype);
517 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n"); 517 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n");
518 html("<head>\n"); 518 html("<head>\n");
519 html("<title>"); 519 html("<title>");
520 html_txt(ctx->page.title); 520 html_txt(ctx->page.title);
521 html("</title>\n"); 521 html("</title>\n");
522 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version); 522 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
523 if (ctx->cfg.robots && *ctx->cfg.robots) 523 if (ctx->cfg.robots && *ctx->cfg.robots)
524 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots); 524 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots);
525 html("<link rel='stylesheet' type='text/css' href='"); 525 html("<link rel='stylesheet' type='text/css' href='");
526 html_attr(ctx->cfg.css); 526 html_attr(ctx->cfg.css);
527 html("'/>\n"); 527 html("'/>\n");
528 if (ctx->cfg.favicon) { 528 if (ctx->cfg.favicon) {
529 html("<link rel='shortcut icon' href='"); 529 html("<link rel='shortcut icon' href='");
530 html_attr(ctx->cfg.favicon); 530 html_attr(ctx->cfg.favicon);
531 html("'/>\n"); 531 html("'/>\n");
532 } 532 }
533 if (host && ctx->repo) { 533 if (host && ctx->repo) {
534 html("<link rel='alternate' title='Atom feed' href='"); 534 html("<link rel='alternate' title='Atom feed' href='");
535 html(cgit_httpscheme()); 535 html(cgit_httpscheme());
536 html_attr(cgit_hosturl()); 536 html_attr(cgit_hosturl());
537 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath, 537 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath,
538 fmt("h=%s", ctx->qry.head))); 538 fmt("h=%s", ctx->qry.head)));
539 html("' type='application/atom+xml'/>\n"); 539 html("' type='application/atom+xml'/>\n");
540 } 540 }
541 if (ctx->cfg.head_include) 541 if (ctx->cfg.head_include)
542 html_include(ctx->cfg.head_include); 542 html_include(ctx->cfg.head_include);
543 html("</head>\n"); 543 html("</head>\n");
544 html("<body>\n"); 544 html("<body>\n");
545 if (ctx->cfg.header) 545 if (ctx->cfg.header)
546 html_include(ctx->cfg.header); 546 html_include(ctx->cfg.header);
547} 547}
548 548
549void cgit_print_docend() 549void cgit_print_docend()
550{ 550{
551 html("</div> <!-- class=content -->\n"); 551 html("</div> <!-- class=content -->\n");
552 if (ctx.cfg.embedded) { 552 if (ctx.cfg.embedded) {
553 html("</div> <!-- id=cgit -->\n"); 553 html("</div> <!-- id=cgit -->\n");
554 if (ctx.cfg.footer) 554 if (ctx.cfg.footer)
555 html_include(ctx.cfg.footer); 555 html_include(ctx.cfg.footer);
556 return; 556 return;
557 } 557 }
558 if (ctx.cfg.footer) 558 if (ctx.cfg.footer)
559 html_include(ctx.cfg.footer); 559 html_include(ctx.cfg.footer);
560 else { 560 else {
561 htmlf("<div class='footer'>generated by cgit %s at ", 561 htmlf("<div class='footer'>generated by cgit %s at ",
562 cgit_version); 562 cgit_version);
563 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time); 563 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time);
564 html("</div>\n"); 564 html("</div>\n");
565 } 565 }
566 html("</div> <!-- id=cgit -->\n"); 566 html("</div> <!-- id=cgit -->\n");
567 html("</body>\n</html>\n"); 567 html("</body>\n</html>\n");
568} 568}
569 569
570int print_branch_option(const char *refname, const unsigned char *sha1, 570int print_branch_option(const char *refname, const unsigned char *sha1,
571 int flags, void *cb_data) 571 int flags, void *cb_data)
572{ 572{
573 char *name = (char *)refname; 573 char *name = (char *)refname;
574 html_option(name, name, ctx.qry.head); 574 html_option(name, name, ctx.qry.head);
575 return 0; 575 return 0;
576} 576}
577 577
578int print_archive_ref(const char *refname, const unsigned char *sha1, 578int print_archive_ref(const char *refname, const unsigned char *sha1,
579 int flags, void *cb_data) 579 int flags, void *cb_data)
580{ 580{
581 struct tag *tag; 581 struct tag *tag;
582 struct taginfo *info; 582 struct taginfo *info;
583 struct object *obj; 583 struct object *obj;
584 char buf[256], *url; 584 char buf[256], *url;
585 unsigned char fileid[20]; 585 unsigned char fileid[20];
586 int *header = (int *)cb_data; 586 int *header = (int *)cb_data;
587 587
588 if (prefixcmp(refname, "refs/archives")) 588 if (prefixcmp(refname, "refs/archives"))
589 return 0; 589 return 0;
590 strncpy(buf, refname+14, sizeof(buf)); 590 strncpy(buf, refname+14, sizeof(buf));
591 obj = parse_object(sha1); 591 obj = parse_object(sha1);
592 if (!obj) 592 if (!obj)
593 return 1; 593 return 1;
594 if (obj->type == OBJ_TAG) { 594 if (obj->type == OBJ_TAG) {
595 tag = lookup_tag(sha1); 595 tag = lookup_tag(sha1);
596 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 596 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
597 return 0; 597 return 0;
598 hashcpy(fileid, tag->tagged->sha1); 598 hashcpy(fileid, tag->tagged->sha1);
599 } else if (obj->type != OBJ_BLOB) { 599 } else if (obj->type != OBJ_BLOB) {
600 return 0; 600 return 0;
601 } else { 601 } else {
602 hashcpy(fileid, sha1); 602 hashcpy(fileid, sha1);
603 } 603 }
604 if (!*header) { 604 if (!*header) {
605 html("<h1>download</h1>\n"); 605 html("<h1>download</h1>\n");
606 *header = 1; 606 *header = 1;
607 } 607 }
608 url = cgit_pageurl(ctx.qry.repo, "blob", 608 url = cgit_pageurl(ctx.qry.repo, "blob",
609 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid), 609 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid),
610 buf)); 610 buf));
611 html_link_open(url, NULL, "menu"); 611 html_link_open(url, NULL, "menu");
612 html_txt(strlpart(buf, 20)); 612 html_txt(strlpart(buf, 20));
613 html_link_close(); 613 html_link_close();
614 return 0; 614 return 0;
615} 615}
616 616
617void cgit_add_hidden_formfields(int incl_head, int incl_search, 617void cgit_add_hidden_formfields(int incl_head, int incl_search,
618 const char *page) 618 const char *page)
619{ 619{
620 char *url; 620 char *url;
621 621
622 if (!ctx.cfg.virtual_root) { 622 if (!ctx.cfg.virtual_root) {
623 url = fmt("%s/%s", ctx.qry.repo, page); 623 url = fmt("%s/%s", ctx.qry.repo, page);
624 if (ctx.qry.vpath) 624 if (ctx.qry.vpath)
625 url = fmt("%s/%s", url, ctx.qry.vpath); 625 url = fmt("%s/%s", url, ctx.qry.vpath);
626 html_hidden("url", url); 626 html_hidden("url", url);
627 } 627 }
628 628
629 if (incl_head && ctx.qry.head && ctx.repo->defbranch && 629 if (incl_head && ctx.qry.head && ctx.repo->defbranch &&
630 strcmp(ctx.qry.head, ctx.repo->defbranch)) 630 strcmp(ctx.qry.head, ctx.repo->defbranch))
631 html_hidden("h", ctx.qry.head); 631 html_hidden("h", ctx.qry.head);
632 632
633 if (ctx.qry.sha1) 633 if (ctx.qry.sha1)
634 html_hidden("id", ctx.qry.sha1); 634 html_hidden("id", ctx.qry.sha1);
635 if (ctx.qry.sha2) 635 if (ctx.qry.sha2)
636 html_hidden("id2", ctx.qry.sha2); 636 html_hidden("id2", ctx.qry.sha2);
637 if (ctx.qry.showmsg) 637 if (ctx.qry.showmsg)
638 html_hidden("showmsg", "1"); 638 html_hidden("showmsg", "1");
639 639
640 if (incl_search) { 640 if (incl_search) {
641 if (ctx.qry.grep) 641 if (ctx.qry.grep)
642 html_hidden("qt", ctx.qry.grep); 642 html_hidden("qt", ctx.qry.grep);
643 if (ctx.qry.search) 643 if (ctx.qry.search)
644 html_hidden("q", ctx.qry.search); 644 html_hidden("q", ctx.qry.search);
645 } 645 }
646} 646}
647 647
648static const char *hc(struct cgit_context *ctx, const char *page) 648static const char *hc(struct cgit_context *ctx, const char *page)
649{ 649{
650 return strcmp(ctx->qry.page, page) ? NULL : "active"; 650 return strcmp(ctx->qry.page, page) ? NULL : "active";
651} 651}
652 652
653static void print_header(struct cgit_context *ctx) 653static void print_header(struct cgit_context *ctx)
654{ 654{
655 html("<table id='header'>\n"); 655 html("<table id='header'>\n");
656 html("<tr>\n"); 656 html("<tr>\n");
657 657
658 if (ctx->cfg.logo && ctx->cfg.logo[0] != 0) { 658 if (ctx->cfg.logo && ctx->cfg.logo[0] != 0) {
659 html("<td class='logo' rowspan='2'><a href='"); 659 html("<td class='logo' rowspan='2'><a href='");
660 if (ctx->cfg.logo_link) 660 if (ctx->cfg.logo_link)
661 html_attr(ctx->cfg.logo_link); 661 html_attr(ctx->cfg.logo_link);
662 else 662 else
663 html_attr(cgit_rooturl()); 663 html_attr(cgit_rooturl());
664 html("'><img src='"); 664 html("'><img src='");
665 html_attr(ctx->cfg.logo); 665 html_attr(ctx->cfg.logo);
666 html("' alt='cgit logo'/></a></td>\n"); 666 html("' alt='cgit logo'/></a></td>\n");
667 } 667 }
668 668
669 html("<td class='main'>"); 669 html("<td class='main'>");
670 if (ctx->repo) { 670 if (ctx->repo) {
671 cgit_index_link("index", NULL, NULL, NULL, 0); 671 cgit_index_link("index", NULL, NULL, NULL, 0);
672 html(" : "); 672 html(" : ");
673 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); 673 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL);
674 html("</td><td class='form'>"); 674 html("</td><td class='form'>");
675 html("<form method='get' action=''>\n"); 675 html("<form method='get' action=''>\n");
676 cgit_add_hidden_formfields(0, 1, ctx->qry.page); 676 cgit_add_hidden_formfields(0, 1, ctx->qry.page);
677 html("<select name='h' onchange='this.form.submit();'>\n"); 677 html("<select name='h' onchange='this.form.submit();'>\n");
678 for_each_branch_ref(print_branch_option, ctx->qry.head); 678 for_each_branch_ref(print_branch_option, ctx->qry.head);
679 html("</select> "); 679 html("</select> ");
680 html("<input type='submit' name='' value='switch'/>"); 680 html("<input type='submit' name='' value='switch'/>");
681 html("</form>"); 681 html("</form>");
682 } else 682 } else
683 html_txt(ctx->cfg.root_title); 683 html_txt(ctx->cfg.root_title);
684 html("</td></tr>\n"); 684 html("</td></tr>\n");
685 685
686 html("<tr><td class='sub'>"); 686 html("<tr><td class='sub'>");
687 if (ctx->repo) { 687 if (ctx->repo) {
688 html_txt(ctx->repo->desc); 688 html_txt(ctx->repo->desc);
689 html("</td><td class='sub right'>"); 689 html("</td><td class='sub right'>");
690 html_txt(ctx->repo->owner); 690 html_txt(ctx->repo->owner);
691 } else { 691 } else {
692 if (ctx->cfg.root_desc) 692 if (ctx->cfg.root_desc)
693 html_txt(ctx->cfg.root_desc); 693 html_txt(ctx->cfg.root_desc);
694 else if (ctx->cfg.index_info) 694 else if (ctx->cfg.index_info)
695 html_include(ctx->cfg.index_info); 695 html_include(ctx->cfg.index_info);
696 } 696 }
697 html("</td></tr></table>\n"); 697 html("</td></tr></table>\n");
698} 698}
699 699
700void cgit_print_pageheader(struct cgit_context *ctx) 700void cgit_print_pageheader(struct cgit_context *ctx)
701{ 701{
702 html("<div id='cgit'>"); 702 html("<div id='cgit'>");
703 if (!ctx->cfg.noheader) 703 if (!ctx->cfg.noheader)
704 print_header(ctx); 704 print_header(ctx);
705 705
706 html("<table class='tabs'><tr><td>\n"); 706 html("<table class='tabs'><tr><td>\n");
707 if (ctx->repo) { 707 if (ctx->repo) {
708 cgit_summary_link("summary", NULL, hc(ctx, "summary"), 708 cgit_summary_link("summary", NULL, hc(ctx, "summary"),
709 ctx->qry.head); 709 ctx->qry.head);
710 cgit_refs_link("refs", NULL, hc(ctx, "refs"), ctx->qry.head, 710 cgit_refs_link("refs", NULL, hc(ctx, "refs"), ctx->qry.head,
711 ctx->qry.sha1, NULL); 711 ctx->qry.sha1, NULL);
712 cgit_log_link("log", NULL, hc(ctx, "log"), ctx->qry.head, 712 cgit_log_link("log", NULL, hc(ctx, "log"), ctx->qry.head,
713 NULL, NULL, 0, NULL, NULL, ctx->qry.showmsg); 713 NULL, NULL, 0, NULL, NULL, ctx->qry.showmsg);
714 cgit_tree_link("tree", NULL, hc(ctx, "tree"), ctx->qry.head, 714 cgit_tree_link("tree", NULL, hc(ctx, "tree"), ctx->qry.head,
715 ctx->qry.sha1, NULL); 715 ctx->qry.sha1, NULL);
716 cgit_commit_link("commit", NULL, hc(ctx, "commit"), 716 cgit_commit_link("commit", NULL, hc(ctx, "commit"),
717 ctx->qry.head, ctx->qry.sha1, 0); 717 ctx->qry.head, ctx->qry.sha1, 0);
718 cgit_diff_link("diff", NULL, hc(ctx, "diff"), ctx->qry.head, 718 cgit_diff_link("diff", NULL, hc(ctx, "diff"), ctx->qry.head,
719 ctx->qry.sha1, ctx->qry.sha2, NULL, 0); 719 ctx->qry.sha1, ctx->qry.sha2, NULL, 0);
720 if (ctx->repo->max_stats) 720 if (ctx->repo->max_stats)
721 cgit_stats_link("stats", NULL, hc(ctx, "stats"), 721 cgit_stats_link("stats", NULL, hc(ctx, "stats"),
722 ctx->qry.head, NULL); 722 ctx->qry.head, NULL);
723 if (ctx->repo->readme) 723 if (ctx->repo->readme)
724 reporevlink("about", "about", NULL, 724 reporevlink("about", "about", NULL,
725 hc(ctx, "about"), ctx->qry.head, NULL, 725 hc(ctx, "about"), ctx->qry.head, NULL,
726 NULL); 726 NULL);
727 html("</td><td class='form'>"); 727 html("</td><td class='form'>");
728 html("<form class='right' method='get' action='"); 728 html("<form class='right' method='get' action='");
729 if (ctx->cfg.virtual_root) 729 if (ctx->cfg.virtual_root)
730 html_url_path(cgit_fileurl(ctx->qry.repo, "log", 730 html_url_path(cgit_fileurl(ctx->qry.repo, "log",
731 ctx->qry.vpath, NULL)); 731 ctx->qry.vpath, NULL));
732 html("'>\n"); 732 html("'>\n");
733 cgit_add_hidden_formfields(1, 0, "log"); 733 cgit_add_hidden_formfields(1, 0, "log");
734 html("<select name='qt'>\n"); 734 html("<select name='qt'>\n");
735 html_option("grep", "log msg", ctx->qry.grep); 735 html_option("grep", "log msg", ctx->qry.grep);
736 html_option("author", "author", ctx->qry.grep); 736 html_option("author", "author", ctx->qry.grep);
737 html_option("committer", "committer", ctx->qry.grep); 737 html_option("committer", "committer", ctx->qry.grep);
738 html("</select>\n"); 738 html("</select>\n");
739 html("<input class='txt' type='text' size='10' name='q' value='"); 739 html("<input class='txt' type='text' size='10' name='q' value='");
740 html_attr(ctx->qry.search); 740 html_attr(ctx->qry.search);
741 html("'/>\n"); 741 html("'/>\n");
742 html("<input type='submit' value='search'/>\n"); 742 html("<input type='submit' value='search'/>\n");
743 html("</form>\n"); 743 html("</form>\n");
744 } else { 744 } else {
745 site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, 0); 745 site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, 0);
746 if (ctx->cfg.root_readme) 746 if (ctx->cfg.root_readme)
747 site_link("about", "about", NULL, hc(ctx, "about"), 747 site_link("about", "about", NULL, hc(ctx, "about"),
748 NULL, 0); 748 NULL, 0);
749 html("</td><td class='form'>"); 749 html("</td><td class='form'>");
750 html("<form method='get' action='"); 750 html("<form method='get' action='");
751 html_attr(cgit_rooturl()); 751 html_attr(cgit_rooturl());
752 html("'>\n"); 752 html("'>\n");
753 html("<input type='text' name='q' size='10' value='"); 753 html("<input type='text' name='q' size='10' value='");
754 html_attr(ctx->qry.search); 754 html_attr(ctx->qry.search);
755 html("'/>\n"); 755 html("'/>\n");
756 html("<input type='submit' value='search'/>\n"); 756 html("<input type='submit' value='search'/>\n");
757 html("</form>"); 757 html("</form>");
758 } 758 }
759 html("</td></tr></table>\n"); 759 html("</td></tr></table>\n");
760 if (ctx->qry.vpath) {
761 html("<div class='path'>");
762 html("path: ");
763 html_txt(ctx->qry.vpath);
764 html("</div>");
765 }
760 html("<div class='content'>"); 766 html("<div class='content'>");
761} 767}
762 768
763void cgit_print_filemode(unsigned short mode) 769void cgit_print_filemode(unsigned short mode)
764{ 770{
765 if (S_ISDIR(mode)) 771 if (S_ISDIR(mode))
766 html("d"); 772 html("d");
767 else if (S_ISLNK(mode)) 773 else if (S_ISLNK(mode))
768 html("l"); 774 html("l");
769 else if (S_ISGITLINK(mode)) 775 else if (S_ISGITLINK(mode))
770 html("m"); 776 html("m");
771 else 777 else
772 html("-"); 778 html("-");
773 html_fileperm(mode >> 6); 779 html_fileperm(mode >> 6);
774 html_fileperm(mode >> 3); 780 html_fileperm(mode >> 3);
775 html_fileperm(mode); 781 html_fileperm(mode);
776} 782}
777 783
778void cgit_print_snapshot_links(const char *repo, const char *head, 784void cgit_print_snapshot_links(const char *repo, const char *head,
779 const char *hex, int snapshots) 785 const char *hex, int snapshots)
780{ 786{
781 const struct cgit_snapshot_format* f; 787 const struct cgit_snapshot_format* f;
782 char *prefix; 788 char *prefix;
783 char *filename; 789 char *filename;
784 unsigned char sha1[20]; 790 unsigned char sha1[20];
785 791
786 if (get_sha1(fmt("refs/tags/%s", hex), sha1) == 0 && 792 if (get_sha1(fmt("refs/tags/%s", hex), sha1) == 0 &&
787 (hex[0] == 'v' || hex[0] == 'V') && isdigit(hex[1])) 793 (hex[0] == 'v' || hex[0] == 'V') && isdigit(hex[1]))
788 hex++; 794 hex++;
789 prefix = xstrdup(fmt("%s-%s", cgit_repobasename(repo), hex)); 795 prefix = xstrdup(fmt("%s-%s", cgit_repobasename(repo), hex));
790 for (f = cgit_snapshot_formats; f->suffix; f++) { 796 for (f = cgit_snapshot_formats; f->suffix; f++) {
791 if (!(snapshots & f->bit)) 797 if (!(snapshots & f->bit))
792 continue; 798 continue;
793 filename = fmt("%s%s", prefix, f->suffix); 799 filename = fmt("%s%s", prefix, f->suffix);
794 cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename); 800 cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename);
795 html("<br/>"); 801 html("<br/>");
796 } 802 }
797} 803}