summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2007-10-27 08:13:42 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2007-10-27 08:53:27 (UTC)
commit763a6a09deec7290365a0072d25630daa7b417e2 (patch) (unidiff)
treed882b72c05ef2b798883e637cba3f53ece12d78c
parentf6310fec783d2721ef61815a0eec525d6a904452 (diff)
downloadcgit-763a6a09deec7290365a0072d25630daa7b417e2.zip
cgit-763a6a09deec7290365a0072d25630daa7b417e2.tar.gz
cgit-763a6a09deec7290365a0072d25630daa7b417e2.tar.bz2
Add support for config param summary-branches
This parameter can be used to specify max number of branches to show on the summary page (if not all branches will be displayed, the "most idle" branches are the ones to be pruned). The default value for this parameter is 0, which disables the pruning. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.h1
-rw-r--r--shared.c3
-rw-r--r--ui-summary.c31
3 files changed, 32 insertions, 3 deletions
diff --git a/cgit.h b/cgit.h
index 53e1336..bb0e64c 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,269 +1,270 @@
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_BLOB 5 28#define CMD_BLOB 5
29#define CMD_SNAPSHOT 6 29#define CMD_SNAPSHOT 6
30#define CMD_TAG 7 30#define CMD_TAG 7
31 31
32/* 32/*
33 * Dateformats used on misc. pages 33 * Dateformats used on misc. pages
34 */ 34 */
35#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S" 35#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S"
36#define FMT_SHORTDATE "%Y-%m-%d" 36#define FMT_SHORTDATE "%Y-%m-%d"
37 37
38 38
39/* 39/*
40 * Limits used for relative dates 40 * Limits used for relative dates
41 */ 41 */
42#define TM_MIN 60 42#define TM_MIN 60
43#define TM_HOUR (TM_MIN * 60) 43#define TM_HOUR (TM_MIN * 60)
44#define TM_DAY (TM_HOUR * 24) 44#define TM_DAY (TM_HOUR * 24)
45#define TM_WEEK (TM_DAY * 7) 45#define TM_WEEK (TM_DAY * 7)
46#define TM_YEAR (TM_DAY * 365) 46#define TM_YEAR (TM_DAY * 365)
47#define TM_MONTH (TM_YEAR / 12.0) 47#define TM_MONTH (TM_YEAR / 12.0)
48 48
49 49
50typedef void (*configfn)(const char *name, const char *value); 50typedef void (*configfn)(const char *name, const char *value);
51typedef void (*filepair_fn)(struct diff_filepair *pair); 51typedef void (*filepair_fn)(struct diff_filepair *pair);
52typedef void (*linediff_fn)(char *line, int len); 52typedef void (*linediff_fn)(char *line, int len);
53 53
54struct cacheitem { 54struct cacheitem {
55 char *name; 55 char *name;
56 struct stat st; 56 struct stat st;
57 int ttl; 57 int ttl;
58 int fd; 58 int fd;
59}; 59};
60 60
61struct repoinfo { 61struct repoinfo {
62 char *url; 62 char *url;
63 char *name; 63 char *name;
64 char *path; 64 char *path;
65 char *desc; 65 char *desc;
66 char *owner; 66 char *owner;
67 char *defbranch; 67 char *defbranch;
68 char *group; 68 char *group;
69 char *module_link; 69 char *module_link;
70 char *readme; 70 char *readme;
71 int snapshots; 71 int snapshots;
72 int enable_log_filecount; 72 int enable_log_filecount;
73 int enable_log_linecount; 73 int enable_log_linecount;
74}; 74};
75 75
76struct repolist { 76struct repolist {
77 int length; 77 int length;
78 int count; 78 int count;
79 struct repoinfo *repos; 79 struct repoinfo *repos;
80}; 80};
81 81
82struct commitinfo { 82struct commitinfo {
83 struct commit *commit; 83 struct commit *commit;
84 char *author; 84 char *author;
85 char *author_email; 85 char *author_email;
86 unsigned long author_date; 86 unsigned long author_date;
87 char *committer; 87 char *committer;
88 char *committer_email; 88 char *committer_email;
89 unsigned long committer_date; 89 unsigned long committer_date;
90 char *subject; 90 char *subject;
91 char *msg; 91 char *msg;
92}; 92};
93 93
94struct taginfo { 94struct taginfo {
95 char *tagger; 95 char *tagger;
96 char *tagger_email; 96 char *tagger_email;
97 int tagger_date; 97 int tagger_date;
98 char *msg; 98 char *msg;
99}; 99};
100 100
101struct refinfo { 101struct refinfo {
102 const char *refname; 102 const char *refname;
103 struct object *object; 103 struct object *object;
104 union { 104 union {
105 struct taginfo *tag; 105 struct taginfo *tag;
106 struct commitinfo *commit; 106 struct commitinfo *commit;
107 }; 107 };
108}; 108};
109 109
110struct reflist { 110struct reflist {
111 struct refinfo **refs; 111 struct refinfo **refs;
112 int alloc; 112 int alloc;
113 int count; 113 int count;
114}; 114};
115 115
116extern const char *cgit_version; 116extern const char *cgit_version;
117 117
118extern struct repolist cgit_repolist; 118extern struct repolist cgit_repolist;
119extern struct repoinfo *cgit_repo; 119extern struct repoinfo *cgit_repo;
120extern int cgit_cmd; 120extern int cgit_cmd;
121 121
122extern char *cgit_root_title; 122extern char *cgit_root_title;
123extern char *cgit_css; 123extern char *cgit_css;
124extern char *cgit_logo; 124extern char *cgit_logo;
125extern char *cgit_index_header; 125extern char *cgit_index_header;
126extern char *cgit_logo_link; 126extern char *cgit_logo_link;
127extern char *cgit_module_link; 127extern char *cgit_module_link;
128extern char *cgit_agefile; 128extern char *cgit_agefile;
129extern char *cgit_virtual_root; 129extern char *cgit_virtual_root;
130extern char *cgit_script_name; 130extern char *cgit_script_name;
131extern char *cgit_cache_root; 131extern char *cgit_cache_root;
132extern char *cgit_repo_group; 132extern char *cgit_repo_group;
133 133
134extern int cgit_nocache; 134extern int cgit_nocache;
135extern int cgit_snapshots; 135extern int cgit_snapshots;
136extern int cgit_enable_index_links; 136extern int cgit_enable_index_links;
137extern int cgit_enable_log_filecount; 137extern int cgit_enable_log_filecount;
138extern int cgit_enable_log_linecount; 138extern int cgit_enable_log_linecount;
139extern int cgit_max_lock_attempts; 139extern int cgit_max_lock_attempts;
140extern int cgit_cache_root_ttl; 140extern int cgit_cache_root_ttl;
141extern int cgit_cache_repo_ttl; 141extern int cgit_cache_repo_ttl;
142extern int cgit_cache_dynamic_ttl; 142extern int cgit_cache_dynamic_ttl;
143extern int cgit_cache_static_ttl; 143extern int cgit_cache_static_ttl;
144extern int cgit_cache_max_create_time; 144extern int cgit_cache_max_create_time;
145extern int cgit_summary_log; 145extern int cgit_summary_log;
146extern int cgit_summary_tags; 146extern int cgit_summary_tags;
147extern int cgit_summary_branches;
147 148
148extern int cgit_max_msg_len; 149extern int cgit_max_msg_len;
149extern int cgit_max_repodesc_len; 150extern int cgit_max_repodesc_len;
150extern int cgit_max_commit_count; 151extern int cgit_max_commit_count;
151 152
152extern int cgit_query_has_symref; 153extern int cgit_query_has_symref;
153extern int cgit_query_has_sha1; 154extern int cgit_query_has_sha1;
154 155
155extern char *cgit_querystring; 156extern char *cgit_querystring;
156extern char *cgit_query_repo; 157extern char *cgit_query_repo;
157extern char *cgit_query_page; 158extern char *cgit_query_page;
158extern char *cgit_query_search; 159extern char *cgit_query_search;
159extern char *cgit_query_head; 160extern char *cgit_query_head;
160extern char *cgit_query_sha1; 161extern char *cgit_query_sha1;
161extern char *cgit_query_sha2; 162extern char *cgit_query_sha2;
162extern char *cgit_query_path; 163extern char *cgit_query_path;
163extern char *cgit_query_name; 164extern char *cgit_query_name;
164extern int cgit_query_ofs; 165extern int cgit_query_ofs;
165 166
166extern int htmlfd; 167extern int htmlfd;
167 168
168extern int cgit_get_cmd_index(const char *cmd); 169extern int cgit_get_cmd_index(const char *cmd);
169extern struct repoinfo *cgit_get_repoinfo(const char *url); 170extern struct repoinfo *cgit_get_repoinfo(const char *url);
170extern void cgit_global_config_cb(const char *name, const char *value); 171extern void cgit_global_config_cb(const char *name, const char *value);
171extern void cgit_repo_config_cb(const char *name, const char *value); 172extern void cgit_repo_config_cb(const char *name, const char *value);
172extern void cgit_querystring_cb(const char *name, const char *value); 173extern void cgit_querystring_cb(const char *name, const char *value);
173 174
174extern int chk_zero(int result, char *msg); 175extern int chk_zero(int result, char *msg);
175extern int chk_positive(int result, char *msg); 176extern int chk_positive(int result, char *msg);
176extern int chk_non_negative(int result, char *msg); 177extern int chk_non_negative(int result, char *msg);
177 178
178extern int hextoint(char c); 179extern int hextoint(char c);
179extern char *trim_end(const char *str, char c); 180extern char *trim_end(const char *str, char c);
180 181
181extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); 182extern void cgit_add_ref(struct reflist *list, struct refinfo *ref);
182extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, 183extern int cgit_refs_cb(const char *refname, const unsigned char *sha1,
183 int flags, void *cb_data); 184 int flags, void *cb_data);
184 185
185extern void *cgit_free_commitinfo(struct commitinfo *info); 186extern void *cgit_free_commitinfo(struct commitinfo *info);
186 187
187extern int cgit_diff_files(const unsigned char *old_sha1, 188extern int cgit_diff_files(const unsigned char *old_sha1,
188 const unsigned char *new_sha1, 189 const unsigned char *new_sha1,
189 linediff_fn fn); 190 linediff_fn fn);
190 191
191extern void cgit_diff_tree(const unsigned char *old_sha1, 192extern void cgit_diff_tree(const unsigned char *old_sha1,
192 const unsigned char *new_sha1, 193 const unsigned char *new_sha1,
193 filepair_fn fn, const char *prefix); 194 filepair_fn fn, const char *prefix);
194 195
195extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 196extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
196 197
197extern char *fmt(const char *format,...); 198extern char *fmt(const char *format,...);
198 199
199extern void html(const char *txt); 200extern void html(const char *txt);
200extern void htmlf(const char *format,...); 201extern void htmlf(const char *format,...);
201extern void html_txt(char *txt); 202extern void html_txt(char *txt);
202extern void html_ntxt(int len, char *txt); 203extern void html_ntxt(int len, char *txt);
203extern void html_attr(char *txt); 204extern void html_attr(char *txt);
204extern void html_hidden(char *name, char *value); 205extern void html_hidden(char *name, char *value);
205extern void html_link_open(char *url, char *title, char *class); 206extern void html_link_open(char *url, char *title, char *class);
206extern void html_link_close(void); 207extern void html_link_close(void);
207extern void html_filemode(unsigned short mode); 208extern void html_filemode(unsigned short mode);
208extern int html_include(const char *filename); 209extern int html_include(const char *filename);
209 210
210extern int cgit_read_config(const char *filename, configfn fn); 211extern int cgit_read_config(const char *filename, configfn fn);
211extern int cgit_parse_query(char *txt, configfn fn); 212extern int cgit_parse_query(char *txt, configfn fn);
212extern struct commitinfo *cgit_parse_commit(struct commit *commit); 213extern struct commitinfo *cgit_parse_commit(struct commit *commit);
213extern struct taginfo *cgit_parse_tag(struct tag *tag); 214extern struct taginfo *cgit_parse_tag(struct tag *tag);
214extern void cgit_parse_url(const char *url); 215extern void cgit_parse_url(const char *url);
215 216
216extern char *cache_safe_filename(const char *unsafe); 217extern char *cache_safe_filename(const char *unsafe);
217extern int cache_lock(struct cacheitem *item); 218extern int cache_lock(struct cacheitem *item);
218extern int cache_unlock(struct cacheitem *item); 219extern int cache_unlock(struct cacheitem *item);
219extern int cache_cancel_lock(struct cacheitem *item); 220extern int cache_cancel_lock(struct cacheitem *item);
220extern int cache_exist(struct cacheitem *item); 221extern int cache_exist(struct cacheitem *item);
221extern int cache_expired(struct cacheitem *item); 222extern int cache_expired(struct cacheitem *item);
222 223
223extern char *cgit_repourl(const char *reponame); 224extern char *cgit_repourl(const char *reponame);
224extern char *cgit_fileurl(const char *reponame, const char *pagename, 225extern char *cgit_fileurl(const char *reponame, const char *pagename,
225 const char *filename, const char *query); 226 const char *filename, const char *query);
226extern char *cgit_pageurl(const char *reponame, const char *pagename, 227extern char *cgit_pageurl(const char *reponame, const char *pagename,
227 const char *query); 228 const char *query);
228 229
229extern const char *cgit_repobasename(const char *reponame); 230extern const char *cgit_repobasename(const char *reponame);
230 231
231extern void cgit_tree_link(char *name, char *title, char *class, char *head, 232extern void cgit_tree_link(char *name, char *title, char *class, char *head,
232 char *rev, char *path); 233 char *rev, char *path);
233extern void cgit_log_link(char *name, char *title, char *class, char *head, 234extern void cgit_log_link(char *name, char *title, char *class, char *head,
234 char *rev, char *path, int ofs); 235 char *rev, char *path, int ofs);
235extern void cgit_commit_link(char *name, char *title, char *class, char *head, 236extern void cgit_commit_link(char *name, char *title, char *class, char *head,
236 char *rev); 237 char *rev);
237extern void cgit_snapshot_link(char *name, char *title, char *class, 238extern void cgit_snapshot_link(char *name, char *title, char *class,
238 char *head, char *rev, char *archivename); 239 char *head, char *rev, char *archivename);
239extern void cgit_diff_link(char *name, char *title, char *class, char *head, 240extern void cgit_diff_link(char *name, char *title, char *class, char *head,
240 char *new_rev, char *old_rev, char *path); 241 char *new_rev, char *old_rev, char *path);
241 242
242extern void cgit_object_link(struct object *obj); 243extern void cgit_object_link(struct object *obj);
243 244
244extern void cgit_print_error(char *msg); 245extern void cgit_print_error(char *msg);
245extern void cgit_print_date(time_t secs, char *format); 246extern void cgit_print_date(time_t secs, char *format);
246extern void cgit_print_age(time_t t, time_t max_relative, char *format); 247extern void cgit_print_age(time_t t, time_t max_relative, char *format);
247extern void cgit_print_docstart(char *title, struct cacheitem *item); 248extern void cgit_print_docstart(char *title, struct cacheitem *item);
248extern void cgit_print_docend(); 249extern void cgit_print_docend();
249extern void cgit_print_pageheader(char *title, int show_search); 250extern void cgit_print_pageheader(char *title, int show_search);
250extern void cgit_print_snapshot_start(const char *mimetype, 251extern void cgit_print_snapshot_start(const char *mimetype,
251 const char *filename, 252 const char *filename,
252 struct cacheitem *item); 253 struct cacheitem *item);
253 254
254extern void cgit_print_repolist(struct cacheitem *item); 255extern void cgit_print_repolist(struct cacheitem *item);
255extern void cgit_print_summary(); 256extern void cgit_print_summary();
256extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path, int pager); 257extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path, int pager);
257extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); 258extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path);
258extern void cgit_print_tree(const char *rev, char *path); 259extern void cgit_print_tree(const char *rev, char *path);
259extern void cgit_print_commit(char *hex); 260extern void cgit_print_commit(char *hex);
260extern void cgit_print_tag(char *revname); 261extern void cgit_print_tag(char *revname);
261extern void cgit_print_diff(const char *new_hex, const char *old_hex, const char *prefix); 262extern void cgit_print_diff(const char *new_hex, const char *old_hex, const char *prefix);
262extern void cgit_print_snapshot(struct cacheitem *item, const char *head, 263extern void cgit_print_snapshot(struct cacheitem *item, const char *head,
263 const char *hex, const char *prefix, 264 const char *hex, const char *prefix,
264 const char *filename, int snapshot); 265 const char *filename, int snapshot);
265extern void cgit_print_snapshot_links(const char *repo, const char *head, 266extern void cgit_print_snapshot_links(const char *repo, const char *head,
266 const char *hex, int snapshots); 267 const char *hex, int snapshots);
267extern int cgit_parse_snapshots_mask(const char *str); 268extern int cgit_parse_snapshots_mask(const char *str);
268 269
269#endif /* CGIT_H */ 270#endif /* CGIT_H */
diff --git a/shared.c b/shared.c
index 7e5eaba..ff600db 100644
--- a/shared.c
+++ b/shared.c
@@ -1,469 +1,472 @@
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
15const char *cgit_version = CGIT_VERSION; 15const char *cgit_version = CGIT_VERSION;
16 16
17char *cgit_root_title = "Git repository browser"; 17char *cgit_root_title = "Git repository browser";
18char *cgit_css = "/cgit.css"; 18char *cgit_css = "/cgit.css";
19char *cgit_logo = "/git-logo.png"; 19char *cgit_logo = "/git-logo.png";
20char *cgit_index_header = NULL; 20char *cgit_index_header = NULL;
21char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/"; 21char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/";
22char *cgit_module_link = "./?repo=%s&page=commit&id=%s"; 22char *cgit_module_link = "./?repo=%s&page=commit&id=%s";
23char *cgit_agefile = "info/web/last-modified"; 23char *cgit_agefile = "info/web/last-modified";
24char *cgit_virtual_root = NULL; 24char *cgit_virtual_root = NULL;
25char *cgit_script_name = CGIT_SCRIPT_NAME; 25char *cgit_script_name = CGIT_SCRIPT_NAME;
26char *cgit_cache_root = CGIT_CACHE_ROOT; 26char *cgit_cache_root = CGIT_CACHE_ROOT;
27char *cgit_repo_group = NULL; 27char *cgit_repo_group = NULL;
28 28
29int cgit_nocache = 0; 29int cgit_nocache = 0;
30int cgit_snapshots = 0; 30int cgit_snapshots = 0;
31int cgit_enable_index_links = 0; 31int cgit_enable_index_links = 0;
32int cgit_enable_log_filecount = 0; 32int cgit_enable_log_filecount = 0;
33int cgit_enable_log_linecount = 0; 33int cgit_enable_log_linecount = 0;
34int cgit_max_lock_attempts = 5; 34int cgit_max_lock_attempts = 5;
35int cgit_cache_root_ttl = 5; 35int cgit_cache_root_ttl = 5;
36int cgit_cache_repo_ttl = 5; 36int cgit_cache_repo_ttl = 5;
37int cgit_cache_dynamic_ttl = 5; 37int cgit_cache_dynamic_ttl = 5;
38int cgit_cache_static_ttl = -1; 38int cgit_cache_static_ttl = -1;
39int cgit_cache_max_create_time = 5; 39int cgit_cache_max_create_time = 5;
40int cgit_summary_log = 0; 40int cgit_summary_log = 0;
41int cgit_summary_tags = 0; 41int cgit_summary_tags = 0;
42int cgit_summary_branches = 0;
42int cgit_renamelimit = -1; 43int cgit_renamelimit = -1;
43 44
44int cgit_max_msg_len = 60; 45int cgit_max_msg_len = 60;
45int cgit_max_repodesc_len = 60; 46int cgit_max_repodesc_len = 60;
46int cgit_max_commit_count = 50; 47int cgit_max_commit_count = 50;
47 48
48int cgit_query_has_symref = 0; 49int cgit_query_has_symref = 0;
49int cgit_query_has_sha1 = 0; 50int cgit_query_has_sha1 = 0;
50 51
51char *cgit_querystring = NULL; 52char *cgit_querystring = NULL;
52char *cgit_query_repo = NULL; 53char *cgit_query_repo = NULL;
53char *cgit_query_page = NULL; 54char *cgit_query_page = NULL;
54char *cgit_query_head = NULL; 55char *cgit_query_head = NULL;
55char *cgit_query_search = NULL; 56char *cgit_query_search = NULL;
56char *cgit_query_sha1 = NULL; 57char *cgit_query_sha1 = NULL;
57char *cgit_query_sha2 = NULL; 58char *cgit_query_sha2 = NULL;
58char *cgit_query_path = NULL; 59char *cgit_query_path = NULL;
59char *cgit_query_name = NULL; 60char *cgit_query_name = NULL;
60int cgit_query_ofs = 0; 61int cgit_query_ofs = 0;
61 62
62int htmlfd = 0; 63int htmlfd = 0;
63 64
64 65
65int cgit_get_cmd_index(const char *cmd) 66int cgit_get_cmd_index(const char *cmd)
66{ 67{
67 static char *cmds[] = {"log", "commit", "diff", "tree", "blob", 68 static char *cmds[] = {"log", "commit", "diff", "tree", "blob",
68 "snapshot", "tag", NULL}; 69 "snapshot", "tag", NULL};
69 int i; 70 int i;
70 71
71 for(i = 0; cmds[i]; i++) 72 for(i = 0; cmds[i]; i++)
72 if (!strcmp(cmd, cmds[i])) 73 if (!strcmp(cmd, cmds[i]))
73 return i + 1; 74 return i + 1;
74 return 0; 75 return 0;
75} 76}
76 77
77int chk_zero(int result, char *msg) 78int chk_zero(int result, char *msg)
78{ 79{
79 if (result != 0) 80 if (result != 0)
80 die("%s: %s", msg, strerror(errno)); 81 die("%s: %s", msg, strerror(errno));
81 return result; 82 return result;
82} 83}
83 84
84int chk_positive(int result, char *msg) 85int chk_positive(int result, char *msg)
85{ 86{
86 if (result <= 0) 87 if (result <= 0)
87 die("%s: %s", msg, strerror(errno)); 88 die("%s: %s", msg, strerror(errno));
88 return result; 89 return result;
89} 90}
90 91
91int chk_non_negative(int result, char *msg) 92int chk_non_negative(int result, char *msg)
92{ 93{
93 if (result < 0) 94 if (result < 0)
94 die("%s: %s",msg, strerror(errno)); 95 die("%s: %s",msg, strerror(errno));
95 return result; 96 return result;
96} 97}
97 98
98struct repoinfo *add_repo(const char *url) 99struct repoinfo *add_repo(const char *url)
99{ 100{
100 struct repoinfo *ret; 101 struct repoinfo *ret;
101 102
102 if (++cgit_repolist.count > cgit_repolist.length) { 103 if (++cgit_repolist.count > cgit_repolist.length) {
103 if (cgit_repolist.length == 0) 104 if (cgit_repolist.length == 0)
104 cgit_repolist.length = 8; 105 cgit_repolist.length = 8;
105 else 106 else
106 cgit_repolist.length *= 2; 107 cgit_repolist.length *= 2;
107 cgit_repolist.repos = xrealloc(cgit_repolist.repos, 108 cgit_repolist.repos = xrealloc(cgit_repolist.repos,
108 cgit_repolist.length * 109 cgit_repolist.length *
109 sizeof(struct repoinfo)); 110 sizeof(struct repoinfo));
110 } 111 }
111 112
112 ret = &cgit_repolist.repos[cgit_repolist.count-1]; 113 ret = &cgit_repolist.repos[cgit_repolist.count-1];
113 ret->url = trim_end(url, '/'); 114 ret->url = trim_end(url, '/');
114 ret->name = ret->url; 115 ret->name = ret->url;
115 ret->path = NULL; 116 ret->path = NULL;
116 ret->desc = NULL; 117 ret->desc = NULL;
117 ret->owner = NULL; 118 ret->owner = NULL;
118 ret->group = cgit_repo_group; 119 ret->group = cgit_repo_group;
119 ret->defbranch = "master"; 120 ret->defbranch = "master";
120 ret->snapshots = cgit_snapshots; 121 ret->snapshots = cgit_snapshots;
121 ret->enable_log_filecount = cgit_enable_log_filecount; 122 ret->enable_log_filecount = cgit_enable_log_filecount;
122 ret->enable_log_linecount = cgit_enable_log_linecount; 123 ret->enable_log_linecount = cgit_enable_log_linecount;
123 ret->module_link = cgit_module_link; 124 ret->module_link = cgit_module_link;
124 ret->readme = NULL; 125 ret->readme = NULL;
125 return ret; 126 return ret;
126} 127}
127 128
128struct repoinfo *cgit_get_repoinfo(const char *url) 129struct repoinfo *cgit_get_repoinfo(const char *url)
129{ 130{
130 int i; 131 int i;
131 struct repoinfo *repo; 132 struct repoinfo *repo;
132 133
133 for (i=0; i<cgit_repolist.count; i++) { 134 for (i=0; i<cgit_repolist.count; i++) {
134 repo = &cgit_repolist.repos[i]; 135 repo = &cgit_repolist.repos[i];
135 if (!strcmp(repo->url, url)) 136 if (!strcmp(repo->url, url))
136 return repo; 137 return repo;
137 } 138 }
138 return NULL; 139 return NULL;
139} 140}
140 141
141void cgit_global_config_cb(const char *name, const char *value) 142void cgit_global_config_cb(const char *name, const char *value)
142{ 143{
143 if (!strcmp(name, "root-title")) 144 if (!strcmp(name, "root-title"))
144 cgit_root_title = xstrdup(value); 145 cgit_root_title = xstrdup(value);
145 else if (!strcmp(name, "css")) 146 else if (!strcmp(name, "css"))
146 cgit_css = xstrdup(value); 147 cgit_css = xstrdup(value);
147 else if (!strcmp(name, "logo")) 148 else if (!strcmp(name, "logo"))
148 cgit_logo = xstrdup(value); 149 cgit_logo = xstrdup(value);
149 else if (!strcmp(name, "index-header")) 150 else if (!strcmp(name, "index-header"))
150 cgit_index_header = xstrdup(value); 151 cgit_index_header = xstrdup(value);
151 else if (!strcmp(name, "logo-link")) 152 else if (!strcmp(name, "logo-link"))
152 cgit_logo_link = xstrdup(value); 153 cgit_logo_link = xstrdup(value);
153 else if (!strcmp(name, "module-link")) 154 else if (!strcmp(name, "module-link"))
154 cgit_module_link = xstrdup(value); 155 cgit_module_link = xstrdup(value);
155 else if (!strcmp(name, "virtual-root")) 156 else if (!strcmp(name, "virtual-root"))
156 cgit_virtual_root = trim_end(value, '/'); 157 cgit_virtual_root = trim_end(value, '/');
157 else if (!strcmp(name, "nocache")) 158 else if (!strcmp(name, "nocache"))
158 cgit_nocache = atoi(value); 159 cgit_nocache = atoi(value);
159 else if (!strcmp(name, "snapshots")) 160 else if (!strcmp(name, "snapshots"))
160 cgit_snapshots = cgit_parse_snapshots_mask(value); 161 cgit_snapshots = cgit_parse_snapshots_mask(value);
161 else if (!strcmp(name, "enable-index-links")) 162 else if (!strcmp(name, "enable-index-links"))
162 cgit_enable_index_links = atoi(value); 163 cgit_enable_index_links = atoi(value);
163 else if (!strcmp(name, "enable-log-filecount")) 164 else if (!strcmp(name, "enable-log-filecount"))
164 cgit_enable_log_filecount = atoi(value); 165 cgit_enable_log_filecount = atoi(value);
165 else if (!strcmp(name, "enable-log-linecount")) 166 else if (!strcmp(name, "enable-log-linecount"))
166 cgit_enable_log_linecount = atoi(value); 167 cgit_enable_log_linecount = atoi(value);
167 else if (!strcmp(name, "cache-root")) 168 else if (!strcmp(name, "cache-root"))
168 cgit_cache_root = xstrdup(value); 169 cgit_cache_root = xstrdup(value);
169 else if (!strcmp(name, "cache-root-ttl")) 170 else if (!strcmp(name, "cache-root-ttl"))
170 cgit_cache_root_ttl = atoi(value); 171 cgit_cache_root_ttl = atoi(value);
171 else if (!strcmp(name, "cache-repo-ttl")) 172 else if (!strcmp(name, "cache-repo-ttl"))
172 cgit_cache_repo_ttl = atoi(value); 173 cgit_cache_repo_ttl = atoi(value);
173 else if (!strcmp(name, "cache-static-ttl")) 174 else if (!strcmp(name, "cache-static-ttl"))
174 cgit_cache_static_ttl = atoi(value); 175 cgit_cache_static_ttl = atoi(value);
175 else if (!strcmp(name, "cache-dynamic-ttl")) 176 else if (!strcmp(name, "cache-dynamic-ttl"))
176 cgit_cache_dynamic_ttl = atoi(value); 177 cgit_cache_dynamic_ttl = atoi(value);
177 else if (!strcmp(name, "max-message-length")) 178 else if (!strcmp(name, "max-message-length"))
178 cgit_max_msg_len = atoi(value); 179 cgit_max_msg_len = atoi(value);
179 else if (!strcmp(name, "max-repodesc-length")) 180 else if (!strcmp(name, "max-repodesc-length"))
180 cgit_max_repodesc_len = atoi(value); 181 cgit_max_repodesc_len = atoi(value);
181 else if (!strcmp(name, "max-commit-count")) 182 else if (!strcmp(name, "max-commit-count"))
182 cgit_max_commit_count = atoi(value); 183 cgit_max_commit_count = atoi(value);
183 else if (!strcmp(name, "summary-log")) 184 else if (!strcmp(name, "summary-log"))
184 cgit_summary_log = atoi(value); 185 cgit_summary_log = atoi(value);
186 else if (!strcmp(name, "summary-branches"))
187 cgit_summary_branches = atoi(value);
185 else if (!strcmp(name, "summary-tags")) 188 else if (!strcmp(name, "summary-tags"))
186 cgit_summary_tags = atoi(value); 189 cgit_summary_tags = atoi(value);
187 else if (!strcmp(name, "agefile")) 190 else if (!strcmp(name, "agefile"))
188 cgit_agefile = xstrdup(value); 191 cgit_agefile = xstrdup(value);
189 else if (!strcmp(name, "renamelimit")) 192 else if (!strcmp(name, "renamelimit"))
190 cgit_renamelimit = atoi(value); 193 cgit_renamelimit = atoi(value);
191 else if (!strcmp(name, "repo.group")) 194 else if (!strcmp(name, "repo.group"))
192 cgit_repo_group = xstrdup(value); 195 cgit_repo_group = xstrdup(value);
193 else if (!strcmp(name, "repo.url")) 196 else if (!strcmp(name, "repo.url"))
194 cgit_repo = add_repo(value); 197 cgit_repo = add_repo(value);
195 else if (!strcmp(name, "repo.name")) 198 else if (!strcmp(name, "repo.name"))
196 cgit_repo->name = xstrdup(value); 199 cgit_repo->name = xstrdup(value);
197 else if (cgit_repo && !strcmp(name, "repo.path")) 200 else if (cgit_repo && !strcmp(name, "repo.path"))
198 cgit_repo->path = trim_end(value, '/'); 201 cgit_repo->path = trim_end(value, '/');
199 else if (cgit_repo && !strcmp(name, "repo.desc")) 202 else if (cgit_repo && !strcmp(name, "repo.desc"))
200 cgit_repo->desc = xstrdup(value); 203 cgit_repo->desc = xstrdup(value);
201 else if (cgit_repo && !strcmp(name, "repo.owner")) 204 else if (cgit_repo && !strcmp(name, "repo.owner"))
202 cgit_repo->owner = xstrdup(value); 205 cgit_repo->owner = xstrdup(value);
203 else if (cgit_repo && !strcmp(name, "repo.defbranch")) 206 else if (cgit_repo && !strcmp(name, "repo.defbranch"))
204 cgit_repo->defbranch = xstrdup(value); 207 cgit_repo->defbranch = xstrdup(value);
205 else if (cgit_repo && !strcmp(name, "repo.snapshots")) 208 else if (cgit_repo && !strcmp(name, "repo.snapshots"))
206 cgit_repo->snapshots = cgit_snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ 209 cgit_repo->snapshots = cgit_snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
207 else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount")) 210 else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount"))
208 cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value); 211 cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value);
209 else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount")) 212 else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount"))
210 cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value); 213 cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value);
211 else if (cgit_repo && !strcmp(name, "repo.module-link")) 214 else if (cgit_repo && !strcmp(name, "repo.module-link"))
212 cgit_repo->module_link= xstrdup(value); 215 cgit_repo->module_link= xstrdup(value);
213 else if (cgit_repo && !strcmp(name, "repo.readme") && value != NULL) { 216 else if (cgit_repo && !strcmp(name, "repo.readme") && value != NULL) {
214 if (*value == '/') 217 if (*value == '/')
215 cgit_repo->readme = xstrdup(value); 218 cgit_repo->readme = xstrdup(value);
216 else 219 else
217 cgit_repo->readme = xstrdup(fmt("%s/%s", cgit_repo->path, value)); 220 cgit_repo->readme = xstrdup(fmt("%s/%s", cgit_repo->path, value));
218 } else if (!strcmp(name, "include")) 221 } else if (!strcmp(name, "include"))
219 cgit_read_config(value, cgit_global_config_cb); 222 cgit_read_config(value, cgit_global_config_cb);
220} 223}
221 224
222void cgit_querystring_cb(const char *name, const char *value) 225void cgit_querystring_cb(const char *name, const char *value)
223{ 226{
224 if (!strcmp(name,"r")) { 227 if (!strcmp(name,"r")) {
225 cgit_query_repo = xstrdup(value); 228 cgit_query_repo = xstrdup(value);
226 cgit_repo = cgit_get_repoinfo(value); 229 cgit_repo = cgit_get_repoinfo(value);
227 } else if (!strcmp(name, "p")) { 230 } else if (!strcmp(name, "p")) {
228 cgit_query_page = xstrdup(value); 231 cgit_query_page = xstrdup(value);
229 cgit_cmd = cgit_get_cmd_index(value); 232 cgit_cmd = cgit_get_cmd_index(value);
230 } else if (!strcmp(name, "url")) { 233 } else if (!strcmp(name, "url")) {
231 cgit_parse_url(value); 234 cgit_parse_url(value);
232 } else if (!strcmp(name, "q")) { 235 } else if (!strcmp(name, "q")) {
233 cgit_query_search = xstrdup(value); 236 cgit_query_search = xstrdup(value);
234 } else if (!strcmp(name, "h")) { 237 } else if (!strcmp(name, "h")) {
235 cgit_query_head = xstrdup(value); 238 cgit_query_head = xstrdup(value);
236 cgit_query_has_symref = 1; 239 cgit_query_has_symref = 1;
237 } else if (!strcmp(name, "id")) { 240 } else if (!strcmp(name, "id")) {
238 cgit_query_sha1 = xstrdup(value); 241 cgit_query_sha1 = xstrdup(value);
239 cgit_query_has_sha1 = 1; 242 cgit_query_has_sha1 = 1;
240 } else if (!strcmp(name, "id2")) { 243 } else if (!strcmp(name, "id2")) {
241 cgit_query_sha2 = xstrdup(value); 244 cgit_query_sha2 = xstrdup(value);
242 cgit_query_has_sha1 = 1; 245 cgit_query_has_sha1 = 1;
243 } else if (!strcmp(name, "ofs")) { 246 } else if (!strcmp(name, "ofs")) {
244 cgit_query_ofs = atoi(value); 247 cgit_query_ofs = atoi(value);
245 } else if (!strcmp(name, "path")) { 248 } else if (!strcmp(name, "path")) {
246 cgit_query_path = trim_end(value, '/'); 249 cgit_query_path = trim_end(value, '/');
247 } else if (!strcmp(name, "name")) { 250 } else if (!strcmp(name, "name")) {
248 cgit_query_name = xstrdup(value); 251 cgit_query_name = xstrdup(value);
249 } 252 }
250} 253}
251 254
252void *cgit_free_commitinfo(struct commitinfo *info) 255void *cgit_free_commitinfo(struct commitinfo *info)
253{ 256{
254 free(info->author); 257 free(info->author);
255 free(info->author_email); 258 free(info->author_email);
256 free(info->committer); 259 free(info->committer);
257 free(info->committer_email); 260 free(info->committer_email);
258 free(info->subject); 261 free(info->subject);
259 free(info); 262 free(info);
260 return NULL; 263 return NULL;
261} 264}
262 265
263int hextoint(char c) 266int hextoint(char c)
264{ 267{
265 if (c >= 'a' && c <= 'f') 268 if (c >= 'a' && c <= 'f')
266 return 10 + c - 'a'; 269 return 10 + c - 'a';
267 else if (c >= 'A' && c <= 'F') 270 else if (c >= 'A' && c <= 'F')
268 return 10 + c - 'A'; 271 return 10 + c - 'A';
269 else if (c >= '0' && c <= '9') 272 else if (c >= '0' && c <= '9')
270 return c - '0'; 273 return c - '0';
271 else 274 else
272 return -1; 275 return -1;
273} 276}
274 277
275char *trim_end(const char *str, char c) 278char *trim_end(const char *str, char c)
276{ 279{
277 int len; 280 int len;
278 char *s, *t; 281 char *s, *t;
279 282
280 if (str == NULL) 283 if (str == NULL)
281 return NULL; 284 return NULL;
282 t = (char *)str; 285 t = (char *)str;
283 len = strlen(t); 286 len = strlen(t);
284 while(len > 0 && t[len - 1] == c) 287 while(len > 0 && t[len - 1] == c)
285 len--; 288 len--;
286 289
287 if (len == 0) 290 if (len == 0)
288 return NULL; 291 return NULL;
289 292
290 c = t[len]; 293 c = t[len];
291 t[len] = '\0'; 294 t[len] = '\0';
292 s = xstrdup(t); 295 s = xstrdup(t);
293 t[len] = c; 296 t[len] = c;
294 return s; 297 return s;
295} 298}
296 299
297void cgit_add_ref(struct reflist *list, struct refinfo *ref) 300void cgit_add_ref(struct reflist *list, struct refinfo *ref)
298{ 301{
299 size_t size; 302 size_t size;
300 303
301 if (list->count >= list->alloc) { 304 if (list->count >= list->alloc) {
302 list->alloc += (list->alloc ? list->alloc : 4); 305 list->alloc += (list->alloc ? list->alloc : 4);
303 size = list->alloc * sizeof(struct refinfo *); 306 size = list->alloc * sizeof(struct refinfo *);
304 list->refs = xrealloc(list->refs, size); 307 list->refs = xrealloc(list->refs, size);
305 } 308 }
306 list->refs[list->count++] = ref; 309 list->refs[list->count++] = ref;
307} 310}
308 311
309struct refinfo *cgit_mk_refinfo(const char *refname, const unsigned char *sha1) 312struct refinfo *cgit_mk_refinfo(const char *refname, const unsigned char *sha1)
310{ 313{
311 struct refinfo *ref; 314 struct refinfo *ref;
312 315
313 ref = xmalloc(sizeof (struct refinfo)); 316 ref = xmalloc(sizeof (struct refinfo));
314 ref->refname = xstrdup(refname); 317 ref->refname = xstrdup(refname);
315 ref->object = parse_object(sha1); 318 ref->object = parse_object(sha1);
316 switch (ref->object->type) { 319 switch (ref->object->type) {
317 case OBJ_TAG: 320 case OBJ_TAG:
318 ref->tag = cgit_parse_tag((struct tag *)ref->object); 321 ref->tag = cgit_parse_tag((struct tag *)ref->object);
319 break; 322 break;
320 case OBJ_COMMIT: 323 case OBJ_COMMIT:
321 ref->commit = cgit_parse_commit((struct commit *)ref->object); 324 ref->commit = cgit_parse_commit((struct commit *)ref->object);
322 break; 325 break;
323 } 326 }
324 return ref; 327 return ref;
325} 328}
326 329
327int cgit_refs_cb(const char *refname, const unsigned char *sha1, int flags, 330int cgit_refs_cb(const char *refname, const unsigned char *sha1, int flags,
328 void *cb_data) 331 void *cb_data)
329{ 332{
330 struct reflist *list = (struct reflist *)cb_data; 333 struct reflist *list = (struct reflist *)cb_data;
331 struct refinfo *info = cgit_mk_refinfo(refname, sha1); 334 struct refinfo *info = cgit_mk_refinfo(refname, sha1);
332 335
333 if (info) 336 if (info)
334 cgit_add_ref(list, info); 337 cgit_add_ref(list, info);
335 return 0; 338 return 0;
336} 339}
337 340
338void cgit_diff_tree_cb(struct diff_queue_struct *q, 341void cgit_diff_tree_cb(struct diff_queue_struct *q,
339 struct diff_options *options, void *data) 342 struct diff_options *options, void *data)
340{ 343{
341 int i; 344 int i;
342 345
343 for (i = 0; i < q->nr; i++) { 346 for (i = 0; i < q->nr; i++) {
344 if (q->queue[i]->status == 'U') 347 if (q->queue[i]->status == 'U')
345 continue; 348 continue;
346 ((filepair_fn)data)(q->queue[i]); 349 ((filepair_fn)data)(q->queue[i]);
347 } 350 }
348} 351}
349 352
350static int load_mmfile(mmfile_t *file, const unsigned char *sha1) 353static int load_mmfile(mmfile_t *file, const unsigned char *sha1)
351{ 354{
352 enum object_type type; 355 enum object_type type;
353 356
354 if (is_null_sha1(sha1)) { 357 if (is_null_sha1(sha1)) {
355 file->ptr = (char *)""; 358 file->ptr = (char *)"";
356 file->size = 0; 359 file->size = 0;
357 } else { 360 } else {
358 file->ptr = read_sha1_file(sha1, &type, 361 file->ptr = read_sha1_file(sha1, &type,
359 (unsigned long *)&file->size); 362 (unsigned long *)&file->size);
360 } 363 }
361 return 1; 364 return 1;
362} 365}
363 366
364/* 367/*
365 * Receive diff-buffers from xdiff and concatenate them as 368 * Receive diff-buffers from xdiff and concatenate them as
366 * needed across multiple callbacks. 369 * needed across multiple callbacks.
367 * 370 *
368 * This is basically a copy of xdiff-interface.c/xdiff_outf(), 371 * This is basically a copy of xdiff-interface.c/xdiff_outf(),
369 * ripped from git and modified to use globals instead of 372 * ripped from git and modified to use globals instead of
370 * a special callback-struct. 373 * a special callback-struct.
371 */ 374 */
372char *diffbuf = NULL; 375char *diffbuf = NULL;
373int buflen = 0; 376int buflen = 0;
374 377
375int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf) 378int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)
376{ 379{
377 int i; 380 int i;
378 381
379 for (i = 0; i < nbuf; i++) { 382 for (i = 0; i < nbuf; i++) {
380 if (mb[i].ptr[mb[i].size-1] != '\n') { 383 if (mb[i].ptr[mb[i].size-1] != '\n') {
381 /* Incomplete line */ 384 /* Incomplete line */
382 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 385 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
383 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 386 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
384 buflen += mb[i].size; 387 buflen += mb[i].size;
385 continue; 388 continue;
386 } 389 }
387 390
388 /* we have a complete line */ 391 /* we have a complete line */
389 if (!diffbuf) { 392 if (!diffbuf) {
390 ((linediff_fn)priv)(mb[i].ptr, mb[i].size); 393 ((linediff_fn)priv)(mb[i].ptr, mb[i].size);
391 continue; 394 continue;
392 } 395 }
393 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 396 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
394 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 397 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
395 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size); 398 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size);
396 free(diffbuf); 399 free(diffbuf);
397 diffbuf = NULL; 400 diffbuf = NULL;
398 buflen = 0; 401 buflen = 0;
399 } 402 }
400 if (diffbuf) { 403 if (diffbuf) {
401 ((linediff_fn)priv)(diffbuf, buflen); 404 ((linediff_fn)priv)(diffbuf, buflen);
402 free(diffbuf); 405 free(diffbuf);
403 diffbuf = NULL; 406 diffbuf = NULL;
404 buflen = 0; 407 buflen = 0;
405 } 408 }
406 return 0; 409 return 0;
407} 410}
408 411
409int cgit_diff_files(const unsigned char *old_sha1, 412int cgit_diff_files(const unsigned char *old_sha1,
410 const unsigned char *new_sha1, 413 const unsigned char *new_sha1,
411 linediff_fn fn) 414 linediff_fn fn)
412{ 415{
413 mmfile_t file1, file2; 416 mmfile_t file1, file2;
414 xpparam_t diff_params; 417 xpparam_t diff_params;
415 xdemitconf_t emit_params; 418 xdemitconf_t emit_params;
416 xdemitcb_t emit_cb; 419 xdemitcb_t emit_cb;
417 420
418 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1)) 421 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1))
419 return 1; 422 return 1;
420 423
421 diff_params.flags = XDF_NEED_MINIMAL; 424 diff_params.flags = XDF_NEED_MINIMAL;
422 emit_params.ctxlen = 3; 425 emit_params.ctxlen = 3;
423 emit_params.flags = XDL_EMIT_FUNCNAMES; 426 emit_params.flags = XDL_EMIT_FUNCNAMES;
424 emit_params.find_func = NULL; 427 emit_params.find_func = NULL;
425 emit_cb.outf = filediff_cb; 428 emit_cb.outf = filediff_cb;
426 emit_cb.priv = fn; 429 emit_cb.priv = fn;
427 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); 430 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb);
428 return 0; 431 return 0;
429} 432}
430 433
431void cgit_diff_tree(const unsigned char *old_sha1, 434void cgit_diff_tree(const unsigned char *old_sha1,
432 const unsigned char *new_sha1, 435 const unsigned char *new_sha1,
433 filepair_fn fn, const char *prefix) 436 filepair_fn fn, const char *prefix)
434{ 437{
435 struct diff_options opt; 438 struct diff_options opt;
436 int ret; 439 int ret;
437 int prefixlen; 440 int prefixlen;
438 441
439 diff_setup(&opt); 442 diff_setup(&opt);
440 opt.output_format = DIFF_FORMAT_CALLBACK; 443 opt.output_format = DIFF_FORMAT_CALLBACK;
441 opt.detect_rename = 1; 444 opt.detect_rename = 1;
442 opt.rename_limit = cgit_renamelimit; 445 opt.rename_limit = cgit_renamelimit;
443 opt.recursive = 1; 446 opt.recursive = 1;
444 opt.format_callback = cgit_diff_tree_cb; 447 opt.format_callback = cgit_diff_tree_cb;
445 opt.format_callback_data = fn; 448 opt.format_callback_data = fn;
446 if (prefix) { 449 if (prefix) {
447 opt.nr_paths = 1; 450 opt.nr_paths = 1;
448 opt.paths = &prefix; 451 opt.paths = &prefix;
449 prefixlen = strlen(prefix); 452 prefixlen = strlen(prefix);
450 opt.pathlens = &prefixlen; 453 opt.pathlens = &prefixlen;
451 } 454 }
452 diff_setup_done(&opt); 455 diff_setup_done(&opt);
453 456
454 if (old_sha1 && !is_null_sha1(old_sha1)) 457 if (old_sha1 && !is_null_sha1(old_sha1))
455 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt); 458 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt);
456 else 459 else
457 ret = diff_root_tree_sha1(new_sha1, "", &opt); 460 ret = diff_root_tree_sha1(new_sha1, "", &opt);
458 diffcore_std(&opt); 461 diffcore_std(&opt);
459 diff_flush(&opt); 462 diff_flush(&opt);
460} 463}
461 464
462void cgit_diff_commit(struct commit *commit, filepair_fn fn) 465void cgit_diff_commit(struct commit *commit, filepair_fn fn)
463{ 466{
464 unsigned char *old_sha1 = NULL; 467 unsigned char *old_sha1 = NULL;
465 468
466 if (commit->parents) 469 if (commit->parents)
467 old_sha1 = commit->parents->item->object.sha1; 470 old_sha1 = commit->parents->item->object.sha1;
468 cgit_diff_tree(old_sha1, commit->object.sha1, fn, NULL); 471 cgit_diff_tree(old_sha1, commit->object.sha1, fn, NULL);
469} 472}
diff --git a/ui-summary.c b/ui-summary.c
index 05170cc..df79d01 100644
--- a/ui-summary.c
+++ b/ui-summary.c
@@ -1,220 +1,245 @@
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 cmp_age(int age1, int age2) 13static int cmp_age(int age1, int age2)
14{ 14{
15 if (age1 != 0 && age2 != 0) 15 if (age1 != 0 && age2 != 0)
16 return age2 - age1; 16 return age2 - age1;
17 17
18 if (age1 == 0 && age2 == 0) 18 if (age1 == 0 && age2 == 0)
19 return 0; 19 return 0;
20 20
21 if (age1 == 0) 21 if (age1 == 0)
22 return +1; 22 return +1;
23 23
24 return -1; 24 return -1;
25} 25}
26 26
27static int cmp_ref_name(const void *a, const void *b)
28{
29 struct refinfo *r1 = *(struct refinfo **)a;
30 struct refinfo *r2 = *(struct refinfo **)b;
31
32 return strcmp(r1->refname, r2->refname);
33}
34
35static int cmp_branch_age(const void *a, const void *b)
36{
37 struct refinfo *r1 = *(struct refinfo **)a;
38 struct refinfo *r2 = *(struct refinfo **)b;
39
40 return cmp_age(r1->commit->committer_date, r2->commit->committer_date);
41}
42
27static int cmp_tag_age(const void *a, const void *b) 43static int cmp_tag_age(const void *a, const void *b)
28{ 44{
29 struct refinfo *r1 = *(struct refinfo **)a; 45 struct refinfo *r1 = *(struct refinfo **)a;
30 struct refinfo *r2 = *(struct refinfo **)b; 46 struct refinfo *r2 = *(struct refinfo **)b;
31 47
32 return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date); 48 return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date);
33} 49}
34 50
35static void cgit_print_branch(struct refinfo *ref) 51static void cgit_print_branch(struct refinfo *ref)
36{ 52{
37 struct commit *commit; 53 struct commit *commit;
38 struct commitinfo *info; 54 struct commitinfo *info;
39 char *name = (char *)ref->refname; 55 char *name = (char *)ref->refname;
40 56
41 commit = lookup_commit(ref->object->sha1); 57 commit = lookup_commit(ref->object->sha1);
42 // object is not really parsed at this point, because of some fallout 58 // object is not really parsed at this point, because of some fallout
43 // from previous calls to git functions in cgit_print_log() 59 // from previous calls to git functions in cgit_print_log()
44 commit->object.parsed = 0; 60 commit->object.parsed = 0;
45 if (commit && !parse_commit(commit)){ 61 if (commit && !parse_commit(commit)){
46 info = cgit_parse_commit(commit); 62 info = cgit_parse_commit(commit);
47 html("<tr><td>"); 63 html("<tr><td>");
48 cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0); 64 cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0);
49 html("</td><td>"); 65 html("</td><td>");
50 cgit_print_age(commit->date, -1, NULL); 66 cgit_print_age(commit->date, -1, NULL);
51 html("</td><td>"); 67 html("</td><td>");
52 html_txt(info->author); 68 html_txt(info->author);
53 html("</td><td>"); 69 html("</td><td>");
54 cgit_commit_link(info->subject, NULL, NULL, name, NULL); 70 cgit_commit_link(info->subject, NULL, NULL, name, NULL);
55 html("</td></tr>\n"); 71 html("</td></tr>\n");
56 cgit_free_commitinfo(info); 72 cgit_free_commitinfo(info);
57 } else { 73 } else {
58 html("<tr><td>"); 74 html("<tr><td>");
59 html_txt(name); 75 html_txt(name);
60 html("</td><td colspan='3'>"); 76 html("</td><td colspan='3'>");
61 htmlf("*** bad ref %s ***", sha1_to_hex(ref->object->sha1)); 77 htmlf("*** bad ref %s ***", sha1_to_hex(ref->object->sha1));
62 html("</td></tr>\n"); 78 html("</td></tr>\n");
63 } 79 }
64} 80}
65 81
66static void print_tag_header() 82static void print_tag_header()
67{ 83{
68 html("<tr class='nohover'><th class='left'>Tag</th>" 84 html("<tr class='nohover'><th class='left'>Tag</th>"
69 "<th class='left'>Age</th>" 85 "<th class='left'>Age</th>"
70 "<th class='left'>Author</th>" 86 "<th class='left'>Author</th>"
71 "<th class='left'>Reference</th></tr>\n"); 87 "<th class='left'>Reference</th></tr>\n");
72 header = 1; 88 header = 1;
73} 89}
74 90
75static int print_tag(struct refinfo *ref) 91static int print_tag(struct refinfo *ref)
76{ 92{
77 struct tag *tag; 93 struct tag *tag;
78 struct taginfo *info; 94 struct taginfo *info;
79 char *url, *name = (char *)ref->refname; 95 char *url, *name = (char *)ref->refname;
80 96
81 if (ref->object->type == OBJ_TAG) { 97 if (ref->object->type == OBJ_TAG) {
82 tag = lookup_tag(ref->object->sha1); 98 tag = lookup_tag(ref->object->sha1);
83 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 99 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
84 return 2; 100 return 2;
85 html("<tr><td>"); 101 html("<tr><td>");
86 url = cgit_pageurl(cgit_query_repo, "tag", 102 url = cgit_pageurl(cgit_query_repo, "tag",
87 fmt("id=%s", name)); 103 fmt("id=%s", name));
88 html_link_open(url, NULL, NULL); 104 html_link_open(url, NULL, NULL);
89 html_txt(name); 105 html_txt(name);
90 html_link_close(); 106 html_link_close();
91 html("</td><td>"); 107 html("</td><td>");
92 if (info->tagger_date > 0) 108 if (info->tagger_date > 0)
93 cgit_print_age(info->tagger_date, -1, NULL); 109 cgit_print_age(info->tagger_date, -1, NULL);
94 html("</td><td>"); 110 html("</td><td>");
95 if (info->tagger) 111 if (info->tagger)
96 html(info->tagger); 112 html(info->tagger);
97 html("</td><td>"); 113 html("</td><td>");
98 cgit_object_link(tag->tagged); 114 cgit_object_link(tag->tagged);
99 html("</td></tr>\n"); 115 html("</td></tr>\n");
100 } else { 116 } else {
101 if (!header) 117 if (!header)
102 print_tag_header(); 118 print_tag_header();
103 html("<tr><td>"); 119 html("<tr><td>");
104 html_txt(name); 120 html_txt(name);
105 html("</td><td colspan='2'/><td>"); 121 html("</td><td colspan='2'/><td>");
106 cgit_object_link(ref->object); 122 cgit_object_link(ref->object);
107 html("</td></tr>\n"); 123 html("</td></tr>\n");
108 } 124 }
109 return 0; 125 return 0;
110} 126}
111 127
112static int cgit_print_archive_cb(const char *refname, const unsigned char *sha1, 128static int cgit_print_archive_cb(const char *refname, const unsigned char *sha1,
113 int flags, void *cb_data) 129 int flags, void *cb_data)
114{ 130{
115 struct tag *tag; 131 struct tag *tag;
116 struct taginfo *info; 132 struct taginfo *info;
117 struct object *obj; 133 struct object *obj;
118 char buf[256], *url; 134 char buf[256], *url;
119 unsigned char fileid[20]; 135 unsigned char fileid[20];
120 136
121 if (prefixcmp(refname, "refs/archives")) 137 if (prefixcmp(refname, "refs/archives"))
122 return 0; 138 return 0;
123 strncpy(buf, refname+14, sizeof(buf)); 139 strncpy(buf, refname+14, sizeof(buf));
124 obj = parse_object(sha1); 140 obj = parse_object(sha1);
125 if (!obj) 141 if (!obj)
126 return 1; 142 return 1;
127 if (obj->type == OBJ_TAG) { 143 if (obj->type == OBJ_TAG) {
128 tag = lookup_tag(sha1); 144 tag = lookup_tag(sha1);
129 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 145 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
130 return 0; 146 return 0;
131 hashcpy(fileid, tag->tagged->sha1); 147 hashcpy(fileid, tag->tagged->sha1);
132 } else if (obj->type != OBJ_BLOB) { 148 } else if (obj->type != OBJ_BLOB) {
133 return 0; 149 return 0;
134 } else { 150 } else {
135 hashcpy(fileid, sha1); 151 hashcpy(fileid, sha1);
136 } 152 }
137 if (!header) { 153 if (!header) {
138 html("<table id='downloads'>"); 154 html("<table id='downloads'>");
139 html("<tr><th>Downloads</th></tr>"); 155 html("<tr><th>Downloads</th></tr>");
140 header = 1; 156 header = 1;
141 } 157 }
142 html("<tr><td>"); 158 html("<tr><td>");
143 url = cgit_pageurl(cgit_query_repo, "blob", 159 url = cgit_pageurl(cgit_query_repo, "blob",
144 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid), 160 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid),
145 buf)); 161 buf));
146 html_link_open(url, NULL, NULL); 162 html_link_open(url, NULL, NULL);
147 html_txt(buf); 163 html_txt(buf);
148 html_link_close(); 164 html_link_close();
149 html("</td></tr>"); 165 html("</td></tr>");
150 return 0; 166 return 0;
151} 167}
152 168
153static void cgit_print_branches() 169static void cgit_print_branches(int maxcount)
154{ 170{
155 struct reflist list; 171 struct reflist list;
156 int i; 172 int i;
157 173
158 html("<tr class='nohover'><th class='left'>Branch</th>" 174 html("<tr class='nohover'><th class='left'>Branch</th>"
159 "<th class='left'>Idle</th>" 175 "<th class='left'>Idle</th>"
160 "<th class='left'>Author</th>" 176 "<th class='left'>Author</th>"
161 "<th class='left'>Head commit</th></tr>\n"); 177 "<th class='left'>Head commit</th></tr>\n");
162 178
163 list.refs = NULL; 179 list.refs = NULL;
164 list.alloc = list.count = 0; 180 list.alloc = list.count = 0;
165 for_each_branch_ref(cgit_refs_cb, &list); 181 for_each_branch_ref(cgit_refs_cb, &list);
166 for(i=0; i<list.count; i++) 182
183 if (maxcount == 0 || maxcount > list.count)
184 maxcount = list.count;
185
186 if (maxcount < list.count) {
187 qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age);
188 qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name);
189 }
190
191 for(i=0; i<maxcount; i++)
167 cgit_print_branch(list.refs[i]); 192 cgit_print_branch(list.refs[i]);
168} 193}
169 194
170static void cgit_print_tags(int maxcount) 195static void cgit_print_tags(int maxcount)
171{ 196{
172 struct reflist list; 197 struct reflist list;
173 int i; 198 int i;
174 199
175 header = 0; 200 header = 0;
176 list.refs = NULL; 201 list.refs = NULL;
177 list.alloc = list.count = 0; 202 list.alloc = list.count = 0;
178 for_each_tag_ref(cgit_refs_cb, &list); 203 for_each_tag_ref(cgit_refs_cb, &list);
179 if (list.count == 0) 204 if (list.count == 0)
180 return; 205 return;
181 qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age); 206 qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age);
182 if (!maxcount) 207 if (!maxcount)
183 maxcount = list.count; 208 maxcount = list.count;
184 else if (maxcount > list.count) 209 else if (maxcount > list.count)
185 maxcount = list.count; 210 maxcount = list.count;
186 print_tag_header(); 211 print_tag_header();
187 for(i=0; i<maxcount; i++) 212 for(i=0; i<maxcount; i++)
188 print_tag(list.refs[i]); 213 print_tag(list.refs[i]);
189} 214}
190 215
191static void cgit_print_archives() 216static void cgit_print_archives()
192{ 217{
193 header = 0; 218 header = 0;
194 for_each_ref(cgit_print_archive_cb, NULL); 219 for_each_ref(cgit_print_archive_cb, NULL);
195 if (header) 220 if (header)
196 html("</table>"); 221 html("</table>");
197} 222}
198 223
199void cgit_print_summary() 224void cgit_print_summary()
200{ 225{
201 html("<div id='summary'>"); 226 html("<div id='summary'>");
202 cgit_print_archives(); 227 cgit_print_archives();
203 html("<h2>"); 228 html("<h2>");
204 html_txt(cgit_repo->name); 229 html_txt(cgit_repo->name);
205 html(" - "); 230 html(" - ");
206 html_txt(cgit_repo->desc); 231 html_txt(cgit_repo->desc);
207 html("</h2>"); 232 html("</h2>");
208 if (cgit_repo->readme) 233 if (cgit_repo->readme)
209 html_include(cgit_repo->readme); 234 html_include(cgit_repo->readme);
210 html("</div>"); 235 html("</div>");
211 if (cgit_summary_log > 0) 236 if (cgit_summary_log > 0)
212 cgit_print_log(cgit_query_head, 0, cgit_summary_log, NULL, NULL, 0); 237 cgit_print_log(cgit_query_head, 0, cgit_summary_log, NULL, NULL, 0);
213 html("<table class='list nowrap'>"); 238 html("<table class='list nowrap'>");
214 if (cgit_summary_log > 0) 239 if (cgit_summary_log > 0)
215 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>"); 240 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>");
216 cgit_print_branches(); 241 cgit_print_branches(cgit_summary_branches);
217 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>"); 242 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>");
218 cgit_print_tags(cgit_summary_tags); 243 cgit_print_tags(cgit_summary_tags);
219 html("</table>"); 244 html("</table>");
220} 245}