summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.css5
-rw-r--r--cgit.h2
-rw-r--r--shared.c4
-rw-r--r--ui-repolist.c10
4 files changed, 21 insertions, 0 deletions
diff --git a/cgit.css b/cgit.css
index 6c7f9c3..5dd43b0 100644
--- a/cgit.css
+++ b/cgit.css
@@ -1,355 +1,360 @@
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: normal; 63 font-weight: normal;
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 { 143td#summary {
144 vertical-align: top; 144 vertical-align: top;
145 padding-bottom: 1em; 145 padding-bottom: 1em;
146} 146}
147 147
148td#archivelist { 148td#archivelist {
149 padding-bottom: 1em; 149 padding-bottom: 1em;
150} 150}
151 151
152td#archivelist table { 152td#archivelist table {
153 float: right; 153 float: right;
154 border-collapse: collapse; 154 border-collapse: collapse;
155 border: solid 1px #777; 155 border: solid 1px #777;
156} 156}
157 157
158td#archivelist table th { 158td#archivelist table th {
159 background-color: #ccc; 159 background-color: #ccc;
160} 160}
161 161
162td#content { 162td#content {
163 padding: 1em 0.5em; 163 padding: 1em 0.5em;
164} 164}
165 165
166div#blob { 166div#blob {
167 border: solid 1px black; 167 border: solid 1px black;
168} 168}
169 169
170div.error { 170div.error {
171 color: red; 171 color: red;
172 font-weight: bold; 172 font-weight: bold;
173 margin: 1em 2em; 173 margin: 1em 2em;
174} 174}
175 175
176td.ls-blob, td.ls-dir, td.ls-mod { 176td.ls-blob, td.ls-dir, td.ls-mod {
177 font-family: monospace; 177 font-family: monospace;
178} 178}
179 179
180div.ls-dir a { 180div.ls-dir a {
181 font-weight: bold; 181 font-weight: bold;
182} 182}
183 183
184th.filesize, td.filesize { 184th.filesize, td.filesize {
185 text-align: right; 185 text-align: right;
186} 186}
187 187
188td.filesize { 188td.filesize {
189 font-family: monospace; 189 font-family: monospace;
190} 190}
191 191
192td.links { 192td.links {
193 font-size: 80%; 193 font-size: 80%;
194 padding-left: 2em; 194 padding-left: 2em;
195} 195}
196 196
197td.filemode { 197td.filemode {
198 font-family: monospace; 198 font-family: monospace;
199} 199}
200 200
201td.blob { 201td.blob {
202 white-space: pre; 202 white-space: pre;
203 font-family: monospace; 203 font-family: monospace;
204 background-color: white; 204 background-color: white;
205} 205}
206 206
207table.nowrap td { 207table.nowrap td {
208 white-space: nowrap; 208 white-space: nowrap;
209} 209}
210 210
211table.commit-info { 211table.commit-info {
212 border-collapse: collapse; 212 border-collapse: collapse;
213 margin-top: 1.5em; 213 margin-top: 1.5em;
214} 214}
215 215
216table.commit-info th { 216table.commit-info th {
217 text-align: left; 217 text-align: left;
218 font-weight: normal; 218 font-weight: normal;
219 padding: 0.1em 1em 0.1em 0.1em; 219 padding: 0.1em 1em 0.1em 0.1em;
220} 220}
221 221
222table.commit-info td { 222table.commit-info td {
223 font-weight: normal; 223 font-weight: normal;
224 padding: 0.1em 1em 0.1em 0.1em; 224 padding: 0.1em 1em 0.1em 0.1em;
225} 225}
226 226
227div.commit-subject { 227div.commit-subject {
228 font-weight: bold; 228 font-weight: bold;
229 font-size: 125%; 229 font-size: 125%;
230 margin: 1.5em 0em 0.5em 0em; 230 margin: 1.5em 0em 0.5em 0em;
231 padding: 0em; 231 padding: 0em;
232} 232}
233 233
234div.commit-msg { 234div.commit-msg {
235 white-space: pre; 235 white-space: pre;
236 font-family: monospace; 236 font-family: monospace;
237} 237}
238 238
239div.diffstat-header { 239div.diffstat-header {
240 font-weight: bold; 240 font-weight: bold;
241 padding-top: 1.5em; 241 padding-top: 1.5em;
242} 242}
243 243
244table.diffstat { 244table.diffstat {
245 border-collapse: collapse; 245 border-collapse: collapse;
246 width: 100%; 246 width: 100%;
247 border: solid 1px #aaa; 247 border: solid 1px #aaa;
248 background-color: #eee; 248 background-color: #eee;
249} 249}
250 250
251table.diffstat tr:hover { 251table.diffstat tr:hover {
252 background-color: #ccc; 252 background-color: #ccc;
253} 253}
254 254
255table.diffstat th { 255table.diffstat th {
256 font-weight: normal; 256 font-weight: normal;
257 text-align: left; 257 text-align: left;
258 text-decoration: underline; 258 text-decoration: underline;
259 padding: 0.1em 1em 0.1em 0.1em; 259 padding: 0.1em 1em 0.1em 0.1em;
260 font-size: 100%; 260 font-size: 100%;
261} 261}
262 262
263table.diffstat td { 263table.diffstat td {
264 padding: 0.2em 0.2em 0.1em 0.1em; 264 padding: 0.2em 0.2em 0.1em 0.1em;
265 font-size: 100%; 265 font-size: 100%;
266 border: none; 266 border: none;
267} 267}
268 268
269table.diffstat td.mode { 269table.diffstat td.mode {
270 white-space: nowrap; 270 white-space: nowrap;
271} 271}
272 272
273table.diffstat td span.modechange { 273table.diffstat td span.modechange {
274 padding-left: 1em; 274 padding-left: 1em;
275 color: red; 275 color: red;
276} 276}
277 277
278table.diffstat td.add a { 278table.diffstat td.add a {
279 color: green; 279 color: green;
280} 280}
281 281
282table.diffstat td.del a { 282table.diffstat td.del a {
283 color: red; 283 color: red;
284} 284}
285 285
286table.diffstat td.upd a { 286table.diffstat td.upd a {
287 color: blue; 287 color: blue;
288} 288}
289 289
290table.diffstat td.graph { 290table.diffstat td.graph {
291 width: 75%; 291 width: 75%;
292 vertical-align: center; 292 vertical-align: center;
293} 293}
294 294
295table.diffstat td.graph table { 295table.diffstat td.graph table {
296 border: none; 296 border: none;
297} 297}
298 298
299table.diffstat td.graph td { 299table.diffstat td.graph td {
300 padding: 0px; 300 padding: 0px;
301 border: 0px; 301 border: 0px;
302 height: 7pt; 302 height: 7pt;
303} 303}
304 304
305table.diffstat td.graph td.add { 305table.diffstat td.graph td.add {
306 background-color: #5c5; 306 background-color: #5c5;
307} 307}
308 308
309table.diffstat td.graph td.rem { 309table.diffstat td.graph td.rem {
310 background-color: #c55; 310 background-color: #c55;
311} 311}
312 312
313table.diffstat td.graph td.none { 313table.diffstat td.graph td.none {
314 background-color: none; 314 background-color: none;
315} 315}
316 316
317div.diffstat-summary { 317div.diffstat-summary {
318 color: #888; 318 color: #888;
319 padding-top: 0.5em; 319 padding-top: 0.5em;
320} 320}
321 321
322table.diff td { 322table.diff td {
323 font-family: monospace; 323 font-family: monospace;
324 white-space: pre; 324 white-space: pre;
325} 325}
326 326
327table.diff td div.head { 327table.diff td div.head {
328 font-weight: bold; 328 font-weight: bold;
329 padding-top: 1em; 329 padding-top: 1em;
330} 330}
331 331
332table.diff td div.hunk { 332table.diff td div.hunk {
333 color: #009; 333 color: #009;
334} 334}
335 335
336table.diff td div.add { 336table.diff td div.add {
337 color: green; 337 color: green;
338} 338}
339 339
340table.diff td div.del { 340table.diff td div.del {
341 color: red; 341 color: red;
342} 342}
343 343
344.sha1 { 344.sha1 {
345 font-family: courier; 345 font-family: courier;
346 font-size: 90%; 346 font-size: 90%;
347} 347}
348 348
349.left { 349.left {
350 text-align: left; 350 text-align: left;
351} 351}
352 352
353.right { 353.right {
354 text-align: right; 354 text-align: right;
355} 355}
356
357table.list td.repogroup {
358 padding-top: 1em;
359 border-bottom: solid 1px #777;
360}
diff --git a/cgit.h b/cgit.h
index e0879bd..8927236 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,203 +1,205 @@
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
32typedef void (*configfn)(const char *name, const char *value); 32typedef void (*configfn)(const char *name, const char *value);
33typedef void (*filepair_fn)(struct diff_filepair *pair); 33typedef void (*filepair_fn)(struct diff_filepair *pair);
34typedef void (*linediff_fn)(char *line, int len); 34typedef void (*linediff_fn)(char *line, int len);
35 35
36struct cacheitem { 36struct cacheitem {
37 char *name; 37 char *name;
38 struct stat st; 38 struct stat st;
39 int ttl; 39 int ttl;
40 int fd; 40 int fd;
41}; 41};
42 42
43struct repoinfo { 43struct repoinfo {
44 char *url; 44 char *url;
45 char *name; 45 char *name;
46 char *path; 46 char *path;
47 char *desc; 47 char *desc;
48 char *owner; 48 char *owner;
49 char *defbranch; 49 char *defbranch;
50 char *group;
50 char *module_link; 51 char *module_link;
51 int snapshots; 52 int snapshots;
52 int enable_log_filecount; 53 int enable_log_filecount;
53 int enable_log_linecount; 54 int enable_log_linecount;
54}; 55};
55 56
56struct repolist { 57struct repolist {
57 int length; 58 int length;
58 int count; 59 int count;
59 struct repoinfo *repos; 60 struct repoinfo *repos;
60}; 61};
61 62
62struct commitinfo { 63struct commitinfo {
63 struct commit *commit; 64 struct commit *commit;
64 char *author; 65 char *author;
65 char *author_email; 66 char *author_email;
66 unsigned long author_date; 67 unsigned long author_date;
67 char *committer; 68 char *committer;
68 char *committer_email; 69 char *committer_email;
69 unsigned long committer_date; 70 unsigned long committer_date;
70 char *subject; 71 char *subject;
71 char *msg; 72 char *msg;
72}; 73};
73 74
74struct taginfo { 75struct taginfo {
75 char *tagger; 76 char *tagger;
76 char *tagger_email; 77 char *tagger_email;
77 int tagger_date; 78 int tagger_date;
78 char *msg; 79 char *msg;
79}; 80};
80 81
81extern const char cgit_version[]; 82extern const char cgit_version[];
82 83
83extern struct repolist cgit_repolist; 84extern struct repolist cgit_repolist;
84extern struct repoinfo *cgit_repo; 85extern struct repoinfo *cgit_repo;
85extern int cgit_cmd; 86extern int cgit_cmd;
86 87
87extern char *cgit_root_title; 88extern char *cgit_root_title;
88extern char *cgit_css; 89extern char *cgit_css;
89extern char *cgit_logo; 90extern char *cgit_logo;
90extern char *cgit_index_header; 91extern char *cgit_index_header;
91extern char *cgit_logo_link; 92extern char *cgit_logo_link;
92extern char *cgit_module_link; 93extern char *cgit_module_link;
93extern char *cgit_virtual_root; 94extern char *cgit_virtual_root;
94extern char *cgit_script_name; 95extern char *cgit_script_name;
95extern char *cgit_cache_root; 96extern char *cgit_cache_root;
97extern char *cgit_repo_group;
96 98
97extern int cgit_nocache; 99extern int cgit_nocache;
98extern int cgit_snapshots; 100extern int cgit_snapshots;
99extern int cgit_enable_log_filecount; 101extern int cgit_enable_log_filecount;
100extern int cgit_enable_log_linecount; 102extern int cgit_enable_log_linecount;
101extern int cgit_max_lock_attempts; 103extern int cgit_max_lock_attempts;
102extern int cgit_cache_root_ttl; 104extern int cgit_cache_root_ttl;
103extern int cgit_cache_repo_ttl; 105extern int cgit_cache_repo_ttl;
104extern int cgit_cache_dynamic_ttl; 106extern int cgit_cache_dynamic_ttl;
105extern int cgit_cache_static_ttl; 107extern int cgit_cache_static_ttl;
106extern int cgit_cache_max_create_time; 108extern int cgit_cache_max_create_time;
107 109
108extern int cgit_max_msg_len; 110extern int cgit_max_msg_len;
109extern int cgit_max_repodesc_len; 111extern int cgit_max_repodesc_len;
110extern int cgit_max_commit_count; 112extern int cgit_max_commit_count;
111 113
112extern int cgit_query_has_symref; 114extern int cgit_query_has_symref;
113extern int cgit_query_has_sha1; 115extern int cgit_query_has_sha1;
114 116
115extern char *cgit_querystring; 117extern char *cgit_querystring;
116extern char *cgit_query_repo; 118extern char *cgit_query_repo;
117extern char *cgit_query_page; 119extern char *cgit_query_page;
118extern char *cgit_query_search; 120extern char *cgit_query_search;
119extern char *cgit_query_head; 121extern char *cgit_query_head;
120extern char *cgit_query_sha1; 122extern char *cgit_query_sha1;
121extern char *cgit_query_sha2; 123extern char *cgit_query_sha2;
122extern char *cgit_query_path; 124extern char *cgit_query_path;
123extern char *cgit_query_name; 125extern char *cgit_query_name;
124extern int cgit_query_ofs; 126extern int cgit_query_ofs;
125 127
126extern int htmlfd; 128extern int htmlfd;
127 129
128extern int cgit_get_cmd_index(const char *cmd); 130extern int cgit_get_cmd_index(const char *cmd);
129extern struct repoinfo *cgit_get_repoinfo(const char *url); 131extern struct repoinfo *cgit_get_repoinfo(const char *url);
130extern void cgit_global_config_cb(const char *name, const char *value); 132extern void cgit_global_config_cb(const char *name, const char *value);
131extern void cgit_repo_config_cb(const char *name, const char *value); 133extern void cgit_repo_config_cb(const char *name, const char *value);
132extern void cgit_querystring_cb(const char *name, const char *value); 134extern void cgit_querystring_cb(const char *name, const char *value);
133 135
134extern int chk_zero(int result, char *msg); 136extern int chk_zero(int result, char *msg);
135extern int chk_positive(int result, char *msg); 137extern int chk_positive(int result, char *msg);
136 138
137extern int hextoint(char c); 139extern int hextoint(char c);
138 140
139extern void *cgit_free_commitinfo(struct commitinfo *info); 141extern void *cgit_free_commitinfo(struct commitinfo *info);
140 142
141extern int cgit_diff_files(const unsigned char *old_sha1, 143extern int cgit_diff_files(const unsigned char *old_sha1,
142 const unsigned char *new_sha1, 144 const unsigned char *new_sha1,
143 linediff_fn fn); 145 linediff_fn fn);
144 146
145extern void cgit_diff_tree(const unsigned char *old_sha1, 147extern void cgit_diff_tree(const unsigned char *old_sha1,
146 const unsigned char *new_sha1, 148 const unsigned char *new_sha1,
147 filepair_fn fn); 149 filepair_fn fn);
148 150
149extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 151extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
150 152
151extern char *fmt(const char *format,...); 153extern char *fmt(const char *format,...);
152 154
153extern void html(const char *txt); 155extern void html(const char *txt);
154extern void htmlf(const char *format,...); 156extern void htmlf(const char *format,...);
155extern void html_txt(char *txt); 157extern void html_txt(char *txt);
156extern void html_ntxt(int len, char *txt); 158extern void html_ntxt(int len, char *txt);
157extern void html_attr(char *txt); 159extern void html_attr(char *txt);
158extern void html_hidden(char *name, char *value); 160extern void html_hidden(char *name, char *value);
159extern void html_link_open(char *url, char *title, char *class); 161extern void html_link_open(char *url, char *title, char *class);
160extern void html_link_close(void); 162extern void html_link_close(void);
161extern void html_filemode(unsigned short mode); 163extern void html_filemode(unsigned short mode);
162extern int html_include(const char *filename); 164extern int html_include(const char *filename);
163 165
164extern int cgit_read_config(const char *filename, configfn fn); 166extern int cgit_read_config(const char *filename, configfn fn);
165extern int cgit_parse_query(char *txt, configfn fn); 167extern int cgit_parse_query(char *txt, configfn fn);
166extern struct commitinfo *cgit_parse_commit(struct commit *commit); 168extern struct commitinfo *cgit_parse_commit(struct commit *commit);
167extern struct taginfo *cgit_parse_tag(struct tag *tag); 169extern struct taginfo *cgit_parse_tag(struct tag *tag);
168extern void cgit_parse_url(const char *url); 170extern void cgit_parse_url(const char *url);
169 171
170extern char *cache_safe_filename(const char *unsafe); 172extern char *cache_safe_filename(const char *unsafe);
171extern int cache_lock(struct cacheitem *item); 173extern int cache_lock(struct cacheitem *item);
172extern int cache_unlock(struct cacheitem *item); 174extern int cache_unlock(struct cacheitem *item);
173extern int cache_cancel_lock(struct cacheitem *item); 175extern int cache_cancel_lock(struct cacheitem *item);
174extern int cache_exist(struct cacheitem *item); 176extern int cache_exist(struct cacheitem *item);
175extern int cache_expired(struct cacheitem *item); 177extern int cache_expired(struct cacheitem *item);
176 178
177extern char *cgit_repourl(const char *reponame); 179extern char *cgit_repourl(const char *reponame);
178extern char *cgit_pageurl(const char *reponame, const char *pagename, 180extern char *cgit_pageurl(const char *reponame, const char *pagename,
179 const char *query); 181 const char *query);
180 182
181extern void cgit_print_error(char *msg); 183extern void cgit_print_error(char *msg);
182extern void cgit_print_date(unsigned long secs); 184extern void cgit_print_date(unsigned long secs);
183extern void cgit_print_docstart(char *title, struct cacheitem *item); 185extern void cgit_print_docstart(char *title, struct cacheitem *item);
184extern void cgit_print_docend(); 186extern void cgit_print_docend();
185extern void cgit_print_pageheader(char *title, int show_search); 187extern void cgit_print_pageheader(char *title, int show_search);
186extern void cgit_print_snapshot_start(const char *mimetype, 188extern void cgit_print_snapshot_start(const char *mimetype,
187 const char *filename, 189 const char *filename,
188 struct cacheitem *item); 190 struct cacheitem *item);
189 191
190extern void cgit_print_repolist(struct cacheitem *item); 192extern void cgit_print_repolist(struct cacheitem *item);
191extern void cgit_print_summary(); 193extern void cgit_print_summary();
192extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path); 194extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path);
193extern void cgit_print_view(const char *hex, char *path); 195extern void cgit_print_view(const char *hex, char *path);
194extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); 196extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path);
195extern void cgit_print_tree(const char *rev, const char *hex, char *path); 197extern void cgit_print_tree(const char *rev, const char *hex, char *path);
196extern void cgit_print_commit(const char *hex); 198extern void cgit_print_commit(const char *hex);
197extern void cgit_print_diff(const char *head, const char *old_hex, const char *new_hex, 199extern void cgit_print_diff(const char *head, const char *old_hex, const char *new_hex,
198 char *path); 200 char *path);
199extern void cgit_print_snapshot(struct cacheitem *item, const char *hex, 201extern void cgit_print_snapshot(struct cacheitem *item, const char *hex,
200 const char *format, const char *prefix, 202 const char *format, const char *prefix,
201 const char *filename); 203 const char *filename);
202 204
203#endif /* CGIT_H */ 205#endif /* CGIT_H */
diff --git a/shared.c b/shared.c
index 45fde7f..65af11a 100644
--- a/shared.c
+++ b/shared.c
@@ -1,361 +1,365 @@
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_virtual_root = NULL; 21char *cgit_virtual_root = NULL;
22char *cgit_script_name = CGIT_SCRIPT_NAME; 22char *cgit_script_name = CGIT_SCRIPT_NAME;
23char *cgit_cache_root = "/var/cache/cgit"; 23char *cgit_cache_root = "/var/cache/cgit";
24char *cgit_repo_group = NULL;
24 25
25int cgit_nocache = 0; 26int cgit_nocache = 0;
26int cgit_snapshots = 0; 27int cgit_snapshots = 0;
27int cgit_enable_log_filecount = 0; 28int cgit_enable_log_filecount = 0;
28int cgit_enable_log_linecount = 0; 29int cgit_enable_log_linecount = 0;
29int cgit_max_lock_attempts = 5; 30int cgit_max_lock_attempts = 5;
30int cgit_cache_root_ttl = 5; 31int cgit_cache_root_ttl = 5;
31int cgit_cache_repo_ttl = 5; 32int cgit_cache_repo_ttl = 5;
32int cgit_cache_dynamic_ttl = 5; 33int cgit_cache_dynamic_ttl = 5;
33int cgit_cache_static_ttl = -1; 34int cgit_cache_static_ttl = -1;
34int cgit_cache_max_create_time = 5; 35int cgit_cache_max_create_time = 5;
35 36
36int cgit_max_msg_len = 60; 37int cgit_max_msg_len = 60;
37int cgit_max_repodesc_len = 60; 38int cgit_max_repodesc_len = 60;
38int cgit_max_commit_count = 50; 39int cgit_max_commit_count = 50;
39 40
40int cgit_query_has_symref = 0; 41int cgit_query_has_symref = 0;
41int cgit_query_has_sha1 = 0; 42int cgit_query_has_sha1 = 0;
42 43
43char *cgit_querystring = NULL; 44char *cgit_querystring = NULL;
44char *cgit_query_repo = NULL; 45char *cgit_query_repo = NULL;
45char *cgit_query_page = NULL; 46char *cgit_query_page = NULL;
46char *cgit_query_head = NULL; 47char *cgit_query_head = NULL;
47char *cgit_query_search = NULL; 48char *cgit_query_search = NULL;
48char *cgit_query_sha1 = NULL; 49char *cgit_query_sha1 = NULL;
49char *cgit_query_sha2 = NULL; 50char *cgit_query_sha2 = NULL;
50char *cgit_query_path = NULL; 51char *cgit_query_path = NULL;
51char *cgit_query_name = NULL; 52char *cgit_query_name = NULL;
52int cgit_query_ofs = 0; 53int cgit_query_ofs = 0;
53 54
54int htmlfd = 0; 55int htmlfd = 0;
55 56
56 57
57int cgit_get_cmd_index(const char *cmd) 58int cgit_get_cmd_index(const char *cmd)
58{ 59{
59 static char *cmds[] = {"log", "commit", "diff", "tree", "view", "blob", "snapshot", NULL}; 60 static char *cmds[] = {"log", "commit", "diff", "tree", "view", "blob", "snapshot", NULL};
60 int i; 61 int i;
61 62
62 for(i = 0; cmds[i]; i++) 63 for(i = 0; cmds[i]; i++)
63 if (!strcmp(cmd, cmds[i])) 64 if (!strcmp(cmd, cmds[i]))
64 return i + 1; 65 return i + 1;
65 return 0; 66 return 0;
66} 67}
67 68
68int chk_zero(int result, char *msg) 69int chk_zero(int result, char *msg)
69{ 70{
70 if (result != 0) 71 if (result != 0)
71 die("%s: %s", msg, strerror(errno)); 72 die("%s: %s", msg, strerror(errno));
72 return result; 73 return result;
73} 74}
74 75
75int chk_positive(int result, char *msg) 76int chk_positive(int result, char *msg)
76{ 77{
77 if (result <= 0) 78 if (result <= 0)
78 die("%s: %s", msg, strerror(errno)); 79 die("%s: %s", msg, strerror(errno));
79 return result; 80 return result;
80} 81}
81 82
82struct repoinfo *add_repo(const char *url) 83struct repoinfo *add_repo(const char *url)
83{ 84{
84 struct repoinfo *ret; 85 struct repoinfo *ret;
85 86
86 if (++cgit_repolist.count > cgit_repolist.length) { 87 if (++cgit_repolist.count > cgit_repolist.length) {
87 if (cgit_repolist.length == 0) 88 if (cgit_repolist.length == 0)
88 cgit_repolist.length = 8; 89 cgit_repolist.length = 8;
89 else 90 else
90 cgit_repolist.length *= 2; 91 cgit_repolist.length *= 2;
91 cgit_repolist.repos = xrealloc(cgit_repolist.repos, 92 cgit_repolist.repos = xrealloc(cgit_repolist.repos,
92 cgit_repolist.length * 93 cgit_repolist.length *
93 sizeof(struct repoinfo)); 94 sizeof(struct repoinfo));
94 } 95 }
95 96
96 ret = &cgit_repolist.repos[cgit_repolist.count-1]; 97 ret = &cgit_repolist.repos[cgit_repolist.count-1];
97 ret->url = xstrdup(url); 98 ret->url = xstrdup(url);
98 ret->name = ret->url; 99 ret->name = ret->url;
99 ret->path = NULL; 100 ret->path = NULL;
100 ret->desc = NULL; 101 ret->desc = NULL;
101 ret->owner = NULL; 102 ret->owner = NULL;
103 ret->group = cgit_repo_group;
102 ret->defbranch = "master"; 104 ret->defbranch = "master";
103 ret->snapshots = cgit_snapshots; 105 ret->snapshots = cgit_snapshots;
104 ret->enable_log_filecount = cgit_enable_log_filecount; 106 ret->enable_log_filecount = cgit_enable_log_filecount;
105 ret->enable_log_linecount = cgit_enable_log_linecount; 107 ret->enable_log_linecount = cgit_enable_log_linecount;
106 ret->module_link = cgit_module_link; 108 ret->module_link = cgit_module_link;
107 return ret; 109 return ret;
108} 110}
109 111
110struct repoinfo *cgit_get_repoinfo(const char *url) 112struct repoinfo *cgit_get_repoinfo(const char *url)
111{ 113{
112 int i; 114 int i;
113 struct repoinfo *repo; 115 struct repoinfo *repo;
114 116
115 for (i=0; i<cgit_repolist.count; i++) { 117 for (i=0; i<cgit_repolist.count; i++) {
116 repo = &cgit_repolist.repos[i]; 118 repo = &cgit_repolist.repos[i];
117 if (!strcmp(repo->url, url)) 119 if (!strcmp(repo->url, url))
118 return repo; 120 return repo;
119 } 121 }
120 return NULL; 122 return NULL;
121} 123}
122 124
123void cgit_global_config_cb(const char *name, const char *value) 125void cgit_global_config_cb(const char *name, const char *value)
124{ 126{
125 if (!strcmp(name, "root-title")) 127 if (!strcmp(name, "root-title"))
126 cgit_root_title = xstrdup(value); 128 cgit_root_title = xstrdup(value);
127 else if (!strcmp(name, "css")) 129 else if (!strcmp(name, "css"))
128 cgit_css = xstrdup(value); 130 cgit_css = xstrdup(value);
129 else if (!strcmp(name, "logo")) 131 else if (!strcmp(name, "logo"))
130 cgit_logo = xstrdup(value); 132 cgit_logo = xstrdup(value);
131 else if (!strcmp(name, "index-header")) 133 else if (!strcmp(name, "index-header"))
132 cgit_index_header = xstrdup(value); 134 cgit_index_header = xstrdup(value);
133 else if (!strcmp(name, "logo-link")) 135 else if (!strcmp(name, "logo-link"))
134 cgit_logo_link = xstrdup(value); 136 cgit_logo_link = xstrdup(value);
135 else if (!strcmp(name, "module-link")) 137 else if (!strcmp(name, "module-link"))
136 cgit_module_link = xstrdup(value); 138 cgit_module_link = xstrdup(value);
137 else if (!strcmp(name, "virtual-root")) 139 else if (!strcmp(name, "virtual-root"))
138 cgit_virtual_root = xstrdup(value); 140 cgit_virtual_root = xstrdup(value);
139 else if (!strcmp(name, "nocache")) 141 else if (!strcmp(name, "nocache"))
140 cgit_nocache = atoi(value); 142 cgit_nocache = atoi(value);
141 else if (!strcmp(name, "snapshots")) 143 else if (!strcmp(name, "snapshots"))
142 cgit_snapshots = atoi(value); 144 cgit_snapshots = atoi(value);
143 else if (!strcmp(name, "enable-log-filecount")) 145 else if (!strcmp(name, "enable-log-filecount"))
144 cgit_enable_log_filecount = atoi(value); 146 cgit_enable_log_filecount = atoi(value);
145 else if (!strcmp(name, "enable-log-linecount")) 147 else if (!strcmp(name, "enable-log-linecount"))
146 cgit_enable_log_linecount = atoi(value); 148 cgit_enable_log_linecount = atoi(value);
147 else if (!strcmp(name, "cache-root")) 149 else if (!strcmp(name, "cache-root"))
148 cgit_cache_root = xstrdup(value); 150 cgit_cache_root = xstrdup(value);
149 else if (!strcmp(name, "cache-root-ttl")) 151 else if (!strcmp(name, "cache-root-ttl"))
150 cgit_cache_root_ttl = atoi(value); 152 cgit_cache_root_ttl = atoi(value);
151 else if (!strcmp(name, "cache-repo-ttl")) 153 else if (!strcmp(name, "cache-repo-ttl"))
152 cgit_cache_repo_ttl = atoi(value); 154 cgit_cache_repo_ttl = atoi(value);
153 else if (!strcmp(name, "cache-static-ttl")) 155 else if (!strcmp(name, "cache-static-ttl"))
154 cgit_cache_static_ttl = atoi(value); 156 cgit_cache_static_ttl = atoi(value);
155 else if (!strcmp(name, "cache-dynamic-ttl")) 157 else if (!strcmp(name, "cache-dynamic-ttl"))
156 cgit_cache_dynamic_ttl = atoi(value); 158 cgit_cache_dynamic_ttl = atoi(value);
157 else if (!strcmp(name, "max-message-length")) 159 else if (!strcmp(name, "max-message-length"))
158 cgit_max_msg_len = atoi(value); 160 cgit_max_msg_len = atoi(value);
159 else if (!strcmp(name, "max-repodesc-length")) 161 else if (!strcmp(name, "max-repodesc-length"))
160 cgit_max_repodesc_len = atoi(value); 162 cgit_max_repodesc_len = atoi(value);
161 else if (!strcmp(name, "max-commit-count")) 163 else if (!strcmp(name, "max-commit-count"))
162 cgit_max_commit_count = atoi(value); 164 cgit_max_commit_count = atoi(value);
165 else if (!strcmp(name, "repo.group"))
166 cgit_repo_group = xstrdup(value);
163 else if (!strcmp(name, "repo.url")) 167 else if (!strcmp(name, "repo.url"))
164 cgit_repo = add_repo(value); 168 cgit_repo = add_repo(value);
165 else if (!strcmp(name, "repo.name")) 169 else if (!strcmp(name, "repo.name"))
166 cgit_repo->name = xstrdup(value); 170 cgit_repo->name = xstrdup(value);
167 else if (cgit_repo && !strcmp(name, "repo.path")) 171 else if (cgit_repo && !strcmp(name, "repo.path"))
168 cgit_repo->path = xstrdup(value); 172 cgit_repo->path = xstrdup(value);
169 else if (cgit_repo && !strcmp(name, "repo.desc")) 173 else if (cgit_repo && !strcmp(name, "repo.desc"))
170 cgit_repo->desc = xstrdup(value); 174 cgit_repo->desc = xstrdup(value);
171 else if (cgit_repo && !strcmp(name, "repo.owner")) 175 else if (cgit_repo && !strcmp(name, "repo.owner"))
172 cgit_repo->owner = xstrdup(value); 176 cgit_repo->owner = xstrdup(value);
173 else if (cgit_repo && !strcmp(name, "repo.defbranch")) 177 else if (cgit_repo && !strcmp(name, "repo.defbranch"))
174 cgit_repo->defbranch = xstrdup(value); 178 cgit_repo->defbranch = xstrdup(value);
175 else if (cgit_repo && !strcmp(name, "repo.snapshots")) 179 else if (cgit_repo && !strcmp(name, "repo.snapshots"))
176 cgit_repo->snapshots = cgit_snapshots * atoi(value); 180 cgit_repo->snapshots = cgit_snapshots * atoi(value);
177 else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount")) 181 else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount"))
178 cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value); 182 cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value);
179 else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount")) 183 else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount"))
180 cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value); 184 cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value);
181 else if (cgit_repo && !strcmp(name, "repo.module-link")) 185 else if (cgit_repo && !strcmp(name, "repo.module-link"))
182 cgit_repo->module_link= xstrdup(value); 186 cgit_repo->module_link= xstrdup(value);
183 else if (!strcmp(name, "include")) 187 else if (!strcmp(name, "include"))
184 cgit_read_config(value, cgit_global_config_cb); 188 cgit_read_config(value, cgit_global_config_cb);
185} 189}
186 190
187void cgit_querystring_cb(const char *name, const char *value) 191void cgit_querystring_cb(const char *name, const char *value)
188{ 192{
189 if (!strcmp(name,"r")) { 193 if (!strcmp(name,"r")) {
190 cgit_query_repo = xstrdup(value); 194 cgit_query_repo = xstrdup(value);
191 cgit_repo = cgit_get_repoinfo(value); 195 cgit_repo = cgit_get_repoinfo(value);
192 } else if (!strcmp(name, "p")) { 196 } else if (!strcmp(name, "p")) {
193 cgit_query_page = xstrdup(value); 197 cgit_query_page = xstrdup(value);
194 cgit_cmd = cgit_get_cmd_index(value); 198 cgit_cmd = cgit_get_cmd_index(value);
195 } else if (!strcmp(name, "url")) { 199 } else if (!strcmp(name, "url")) {
196 cgit_parse_url(value); 200 cgit_parse_url(value);
197 } else if (!strcmp(name, "q")) { 201 } else if (!strcmp(name, "q")) {
198 cgit_query_search = xstrdup(value); 202 cgit_query_search = xstrdup(value);
199 } else if (!strcmp(name, "h")) { 203 } else if (!strcmp(name, "h")) {
200 cgit_query_head = xstrdup(value); 204 cgit_query_head = xstrdup(value);
201 cgit_query_has_symref = 1; 205 cgit_query_has_symref = 1;
202 } else if (!strcmp(name, "id")) { 206 } else if (!strcmp(name, "id")) {
203 cgit_query_sha1 = xstrdup(value); 207 cgit_query_sha1 = xstrdup(value);
204 cgit_query_has_sha1 = 1; 208 cgit_query_has_sha1 = 1;
205 } else if (!strcmp(name, "id2")) { 209 } else if (!strcmp(name, "id2")) {
206 cgit_query_sha2 = xstrdup(value); 210 cgit_query_sha2 = xstrdup(value);
207 cgit_query_has_sha1 = 1; 211 cgit_query_has_sha1 = 1;
208 } else if (!strcmp(name, "ofs")) { 212 } else if (!strcmp(name, "ofs")) {
209 cgit_query_ofs = atoi(value); 213 cgit_query_ofs = atoi(value);
210 } else if (!strcmp(name, "path")) { 214 } else if (!strcmp(name, "path")) {
211 cgit_query_path = xstrdup(value); 215 cgit_query_path = xstrdup(value);
212 } else if (!strcmp(name, "name")) { 216 } else if (!strcmp(name, "name")) {
213 cgit_query_name = xstrdup(value); 217 cgit_query_name = xstrdup(value);
214 } 218 }
215} 219}
216 220
217void *cgit_free_commitinfo(struct commitinfo *info) 221void *cgit_free_commitinfo(struct commitinfo *info)
218{ 222{
219 free(info->author); 223 free(info->author);
220 free(info->author_email); 224 free(info->author_email);
221 free(info->committer); 225 free(info->committer);
222 free(info->committer_email); 226 free(info->committer_email);
223 free(info->subject); 227 free(info->subject);
224 free(info); 228 free(info);
225 return NULL; 229 return NULL;
226} 230}
227 231
228int hextoint(char c) 232int hextoint(char c)
229{ 233{
230 if (c >= 'a' && c <= 'f') 234 if (c >= 'a' && c <= 'f')
231 return 10 + c - 'a'; 235 return 10 + c - 'a';
232 else if (c >= 'A' && c <= 'F') 236 else if (c >= 'A' && c <= 'F')
233 return 10 + c - 'A'; 237 return 10 + c - 'A';
234 else if (c >= '0' && c <= '9') 238 else if (c >= '0' && c <= '9')
235 return c - '0'; 239 return c - '0';
236 else 240 else
237 return -1; 241 return -1;
238} 242}
239 243
240void cgit_diff_tree_cb(struct diff_queue_struct *q, 244void cgit_diff_tree_cb(struct diff_queue_struct *q,
241 struct diff_options *options, void *data) 245 struct diff_options *options, void *data)
242{ 246{
243 int i; 247 int i;
244 248
245 for (i = 0; i < q->nr; i++) { 249 for (i = 0; i < q->nr; i++) {
246 if (q->queue[i]->status == 'U') 250 if (q->queue[i]->status == 'U')
247 continue; 251 continue;
248 ((filepair_fn)data)(q->queue[i]); 252 ((filepair_fn)data)(q->queue[i]);
249 } 253 }
250} 254}
251 255
252static int load_mmfile(mmfile_t *file, const unsigned char *sha1) 256static int load_mmfile(mmfile_t *file, const unsigned char *sha1)
253{ 257{
254 enum object_type type; 258 enum object_type type;
255 259
256 if (is_null_sha1(sha1)) { 260 if (is_null_sha1(sha1)) {
257 file->ptr = (char *)""; 261 file->ptr = (char *)"";
258 file->size = 0; 262 file->size = 0;
259 } else { 263 } else {
260 file->ptr = read_sha1_file(sha1, &type, &file->size); 264 file->ptr = read_sha1_file(sha1, &type, &file->size);
261 } 265 }
262 return 1; 266 return 1;
263} 267}
264 268
265/* 269/*
266 * Receive diff-buffers from xdiff and concatenate them as 270 * Receive diff-buffers from xdiff and concatenate them as
267 * needed across multiple callbacks. 271 * needed across multiple callbacks.
268 * 272 *
269 * This is basically a copy of xdiff-interface.c/xdiff_outf(), 273 * This is basically a copy of xdiff-interface.c/xdiff_outf(),
270 * ripped from git and modified to use globals instead of 274 * ripped from git and modified to use globals instead of
271 * a special callback-struct. 275 * a special callback-struct.
272 */ 276 */
273char *diffbuf = NULL; 277char *diffbuf = NULL;
274int buflen = 0; 278int buflen = 0;
275 279
276int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf) 280int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)
277{ 281{
278 int i; 282 int i;
279 283
280 for (i = 0; i < nbuf; i++) { 284 for (i = 0; i < nbuf; i++) {
281 if (mb[i].ptr[mb[i].size-1] != '\n') { 285 if (mb[i].ptr[mb[i].size-1] != '\n') {
282 /* Incomplete line */ 286 /* Incomplete line */
283 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 287 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
284 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 288 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
285 buflen += mb[i].size; 289 buflen += mb[i].size;
286 continue; 290 continue;
287 } 291 }
288 292
289 /* we have a complete line */ 293 /* we have a complete line */
290 if (!diffbuf) { 294 if (!diffbuf) {
291 ((linediff_fn)priv)(mb[i].ptr, mb[i].size); 295 ((linediff_fn)priv)(mb[i].ptr, mb[i].size);
292 continue; 296 continue;
293 } 297 }
294 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 298 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
295 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 299 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
296 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size); 300 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size);
297 free(diffbuf); 301 free(diffbuf);
298 diffbuf = NULL; 302 diffbuf = NULL;
299 buflen = 0; 303 buflen = 0;
300 } 304 }
301 if (diffbuf) { 305 if (diffbuf) {
302 ((linediff_fn)priv)(diffbuf, buflen); 306 ((linediff_fn)priv)(diffbuf, buflen);
303 free(diffbuf); 307 free(diffbuf);
304 diffbuf = NULL; 308 diffbuf = NULL;
305 buflen = 0; 309 buflen = 0;
306 } 310 }
307 return 0; 311 return 0;
308} 312}
309 313
310int cgit_diff_files(const unsigned char *old_sha1, 314int cgit_diff_files(const unsigned char *old_sha1,
311 const unsigned char *new_sha1, 315 const unsigned char *new_sha1,
312 linediff_fn fn) 316 linediff_fn fn)
313{ 317{
314 mmfile_t file1, file2; 318 mmfile_t file1, file2;
315 xpparam_t diff_params; 319 xpparam_t diff_params;
316 xdemitconf_t emit_params; 320 xdemitconf_t emit_params;
317 xdemitcb_t emit_cb; 321 xdemitcb_t emit_cb;
318 322
319 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1)) 323 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1))
320 return 1; 324 return 1;
321 325
322 diff_params.flags = XDF_NEED_MINIMAL; 326 diff_params.flags = XDF_NEED_MINIMAL;
323 emit_params.ctxlen = 3; 327 emit_params.ctxlen = 3;
324 emit_params.flags = XDL_EMIT_FUNCNAMES; 328 emit_params.flags = XDL_EMIT_FUNCNAMES;
325 emit_cb.outf = filediff_cb; 329 emit_cb.outf = filediff_cb;
326 emit_cb.priv = fn; 330 emit_cb.priv = fn;
327 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); 331 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb);
328 return 0; 332 return 0;
329} 333}
330 334
331void cgit_diff_tree(const unsigned char *old_sha1, 335void cgit_diff_tree(const unsigned char *old_sha1,
332 const unsigned char *new_sha1, 336 const unsigned char *new_sha1,
333 filepair_fn fn) 337 filepair_fn fn)
334{ 338{
335 struct diff_options opt; 339 struct diff_options opt;
336 int ret; 340 int ret;
337 341
338 diff_setup(&opt); 342 diff_setup(&opt);
339 opt.output_format = DIFF_FORMAT_CALLBACK; 343 opt.output_format = DIFF_FORMAT_CALLBACK;
340 opt.detect_rename = 1; 344 opt.detect_rename = 1;
341 opt.recursive = 1; 345 opt.recursive = 1;
342 opt.format_callback = cgit_diff_tree_cb; 346 opt.format_callback = cgit_diff_tree_cb;
343 opt.format_callback_data = fn; 347 opt.format_callback_data = fn;
344 diff_setup_done(&opt); 348 diff_setup_done(&opt);
345 349
346 if (old_sha1) 350 if (old_sha1)
347 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt); 351 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt);
348 else 352 else
349 ret = diff_root_tree_sha1(new_sha1, "", &opt); 353 ret = diff_root_tree_sha1(new_sha1, "", &opt);
350 diffcore_std(&opt); 354 diffcore_std(&opt);
351 diff_flush(&opt); 355 diff_flush(&opt);
352} 356}
353 357
354void cgit_diff_commit(struct commit *commit, filepair_fn fn) 358void cgit_diff_commit(struct commit *commit, filepair_fn fn)
355{ 359{
356 unsigned char *old_sha1 = NULL; 360 unsigned char *old_sha1 = NULL;
357 361
358 if (commit->parents) 362 if (commit->parents)
359 old_sha1 = commit->parents->item->object.sha1; 363 old_sha1 = commit->parents->item->object.sha1;
360 cgit_diff_tree(old_sha1, commit->object.sha1, fn); 364 cgit_diff_tree(old_sha1, commit->object.sha1, fn);
361} 365}
diff --git a/ui-repolist.c b/ui-repolist.c
index 8e367a2..33e3e7f 100644
--- a/ui-repolist.c
+++ b/ui-repolist.c
@@ -1,58 +1,68 @@
1/* ui-repolist.c: functions for generating the repolist page 1/* ui-repolist.c: functions for generating the repolist 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
11void cgit_print_repolist(struct cacheitem *item) 11void cgit_print_repolist(struct cacheitem *item)
12{ 12{
13 struct repoinfo *repo; 13 struct repoinfo *repo;
14 int i; 14 int i;
15 char *last_group = NULL;
15 16
16 cgit_print_docstart(cgit_root_title, item); 17 cgit_print_docstart(cgit_root_title, item);
17 cgit_print_pageheader(cgit_root_title, 0); 18 cgit_print_pageheader(cgit_root_title, 0);
18 19
19 html("<table class='list nowrap'>"); 20 html("<table class='list nowrap'>");
20 if (cgit_index_header) { 21 if (cgit_index_header) {
21 html("<tr class='nohover'><td colspan='4' class='include-block'>"); 22 html("<tr class='nohover'><td colspan='4' class='include-block'>");
22 html_include(cgit_index_header); 23 html_include(cgit_index_header);
23 html("</td></tr>"); 24 html("</td></tr>");
24 } 25 }
25 html("<tr class='nohover'>" 26 html("<tr class='nohover'>"
26 "<th class='left'>Name</th>" 27 "<th class='left'>Name</th>"
27 "<th class='left'>Description</th>" 28 "<th class='left'>Description</th>"
28 "<th class='left'>Owner</th>" 29 "<th class='left'>Owner</th>"
29 "<th class='left'>Links</th></tr>\n"); 30 "<th class='left'>Links</th></tr>\n");
30 31
31 for (i=0; i<cgit_repolist.count; i++) { 32 for (i=0; i<cgit_repolist.count; i++) {
32 repo = &cgit_repolist.repos[i]; 33 repo = &cgit_repolist.repos[i];
34 if ((last_group == NULL && repo->group != NULL) ||
35 (last_group != NULL && repo->group == NULL) ||
36 (last_group != NULL && repo->group!= NULL &&
37 strcmp(repo->group, last_group))) {
38 html("<tr class='nohover'><td colspan='4' class='repogroup'>");
39 html_txt(repo->group);
40 html("</td></tr>");
41 last_group = repo->group;
42 }
33 html("<tr><td>"); 43 html("<tr><td>");
34 html_link_open(cgit_repourl(repo->url), NULL, NULL); 44 html_link_open(cgit_repourl(repo->url), NULL, NULL);
35 html_txt(repo->name); 45 html_txt(repo->name);
36 html_link_close(); 46 html_link_close();
37 html("</td><td>"); 47 html("</td><td>");
38 html_ntxt(cgit_max_repodesc_len, repo->desc); 48 html_ntxt(cgit_max_repodesc_len, repo->desc);
39 html("</td><td>"); 49 html("</td><td>");
40 html_txt(repo->owner); 50 html_txt(repo->owner);
41 html("</td><td>"); 51 html("</td><td>");
42 html_link_open(cgit_pageurl(repo->name, "commit", NULL), 52 html_link_open(cgit_pageurl(repo->name, "commit", NULL),
43 "Commit: display last commit", NULL); 53 "Commit: display last commit", NULL);
44 html("C</a> "); 54 html("C</a> ");
45 html_link_open(cgit_pageurl(repo->name, "diff", NULL), 55 html_link_open(cgit_pageurl(repo->name, "diff", NULL),
46 "Diff: see changes introduced by last commit", NULL); 56 "Diff: see changes introduced by last commit", NULL);
47 html("D</a> "); 57 html("D</a> ");
48 html_link_open(cgit_pageurl(repo->name, "log", NULL), 58 html_link_open(cgit_pageurl(repo->name, "log", NULL),
49 "Log: show history of the main branch", NULL); 59 "Log: show history of the main branch", NULL);
50 html("L</a> "); 60 html("L</a> ");
51 html_link_open(cgit_pageurl(repo->name, "tree", NULL), 61 html_link_open(cgit_pageurl(repo->name, "tree", NULL),
52 "Tree: browse the files in the main branch", NULL); 62 "Tree: browse the files in the main branch", NULL);
53 html("T</a>"); 63 html("T</a>");
54 html("</td></tr>\n"); 64 html("</td></tr>\n");
55 } 65 }
56 html("</table>"); 66 html("</table>");
57 cgit_print_docend(); 67 cgit_print_docend();
58} 68}