summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2007-05-13 15:15:06 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2007-05-13 15:15:06 (UTC)
commitc6cf3a424a0860d69b290254d9b19d35527b2d27 (patch) (unidiff)
tree2874f2c42e907cba1187ae32ee686daebc2de59e
parent80e577c3ef2a73becabff7e9c9c242f317a87de9 (diff)
downloadcgit-c6cf3a424a0860d69b290254d9b19d35527b2d27.zip
cgit-c6cf3a424a0860d69b290254d9b19d35527b2d27.tar.gz
cgit-c6cf3a424a0860d69b290254d9b19d35527b2d27.tar.bz2
Add max-commit-count parameter to cgitrc
This enabled customizing number of commits shown per page in log view. It also changes the default from 100 to 50, mainly due to the more cpu intensive log pages (number of files/lines changed) but also since 100 log messages requires excessive scrolling. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c4
-rw-r--r--cgit.h1
-rw-r--r--cgitrc4
-rw-r--r--shared.c3
4 files changed, 10 insertions, 2 deletions
diff --git a/cgit.c b/cgit.c
index 28bab8d..aee7ba3 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,259 +1,259 @@
1/* cgit.c: cgi for the git scm 1/* cgit.c: cgi for the git scm
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
11const char cgit_version[] = CGIT_VERSION; 11const char cgit_version[] = CGIT_VERSION;
12 12
13 13
14static struct repoinfo *cgit_get_repoinfo(char *url) 14static struct repoinfo *cgit_get_repoinfo(char *url)
15{ 15{
16 int i; 16 int i;
17 struct repoinfo *repo; 17 struct repoinfo *repo;
18 18
19 for (i=0; i<cgit_repolist.count; i++) { 19 for (i=0; i<cgit_repolist.count; i++) {
20 repo = &cgit_repolist.repos[i]; 20 repo = &cgit_repolist.repos[i];
21 if (!strcmp(repo->url, url)) 21 if (!strcmp(repo->url, url))
22 return repo; 22 return repo;
23 } 23 }
24 return NULL; 24 return NULL;
25} 25}
26 26
27 27
28static int cgit_prepare_cache(struct cacheitem *item) 28static int cgit_prepare_cache(struct cacheitem *item)
29{ 29{
30 if (!cgit_query_repo) { 30 if (!cgit_query_repo) {
31 item->name = xstrdup(fmt("%s/index.html", cgit_cache_root)); 31 item->name = xstrdup(fmt("%s/index.html", cgit_cache_root));
32 item->ttl = cgit_cache_root_ttl; 32 item->ttl = cgit_cache_root_ttl;
33 return 1; 33 return 1;
34 } 34 }
35 cgit_repo = cgit_get_repoinfo(cgit_query_repo); 35 cgit_repo = cgit_get_repoinfo(cgit_query_repo);
36 if (!cgit_repo) { 36 if (!cgit_repo) {
37 char *title = fmt("%s - %s", cgit_root_title, "Bad request"); 37 char *title = fmt("%s - %s", cgit_root_title, "Bad request");
38 cgit_print_docstart(title, item); 38 cgit_print_docstart(title, item);
39 cgit_print_pageheader(title, 0); 39 cgit_print_pageheader(title, 0);
40 cgit_print_error(fmt("Unknown repo: %s", cgit_query_repo)); 40 cgit_print_error(fmt("Unknown repo: %s", cgit_query_repo));
41 cgit_print_docend(); 41 cgit_print_docend();
42 return 0; 42 return 0;
43 } 43 }
44 44
45 if (!cgit_query_page) { 45 if (!cgit_query_page) {
46 item->name = xstrdup(fmt("%s/%s/index.html", cgit_cache_root, 46 item->name = xstrdup(fmt("%s/%s/index.html", cgit_cache_root,
47 cgit_repo->url)); 47 cgit_repo->url));
48 item->ttl = cgit_cache_repo_ttl; 48 item->ttl = cgit_cache_repo_ttl;
49 } else { 49 } else {
50 item->name = xstrdup(fmt("%s/%s/%s/%s.html", cgit_cache_root, 50 item->name = xstrdup(fmt("%s/%s/%s/%s.html", cgit_cache_root,
51 cgit_repo->url, cgit_query_page, 51 cgit_repo->url, cgit_query_page,
52 cache_safe_filename(cgit_querystring))); 52 cache_safe_filename(cgit_querystring)));
53 if (cgit_query_has_symref) 53 if (cgit_query_has_symref)
54 item->ttl = cgit_cache_dynamic_ttl; 54 item->ttl = cgit_cache_dynamic_ttl;
55 else if (cgit_query_has_sha1) 55 else if (cgit_query_has_sha1)
56 item->ttl = cgit_cache_static_ttl; 56 item->ttl = cgit_cache_static_ttl;
57 else 57 else
58 item->ttl = cgit_cache_repo_ttl; 58 item->ttl = cgit_cache_repo_ttl;
59 } 59 }
60 return 1; 60 return 1;
61} 61}
62 62
63static void cgit_print_repo_page(struct cacheitem *item) 63static void cgit_print_repo_page(struct cacheitem *item)
64{ 64{
65 char *title; 65 char *title;
66 int show_search; 66 int show_search;
67 67
68 if (chdir(cgit_repo->path)) { 68 if (chdir(cgit_repo->path)) {
69 title = fmt("%s - %s", cgit_root_title, "Bad request"); 69 title = fmt("%s - %s", cgit_root_title, "Bad request");
70 cgit_print_docstart(title, item); 70 cgit_print_docstart(title, item);
71 cgit_print_pageheader(title, 0); 71 cgit_print_pageheader(title, 0);
72 cgit_print_error(fmt("Unable to scan repository: %s", 72 cgit_print_error(fmt("Unable to scan repository: %s",
73 strerror(errno))); 73 strerror(errno)));
74 cgit_print_docend(); 74 cgit_print_docend();
75 return; 75 return;
76 } 76 }
77 77
78 title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc); 78 title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc);
79 show_search = 0; 79 show_search = 0;
80 setenv("GIT_DIR", cgit_repo->path, 1); 80 setenv("GIT_DIR", cgit_repo->path, 1);
81 81
82 if (cgit_query_page) { 82 if (cgit_query_page) {
83 if (cgit_repo->snapshots && !strcmp(cgit_query_page, "snapshot")) { 83 if (cgit_repo->snapshots && !strcmp(cgit_query_page, "snapshot")) {
84 cgit_print_snapshot(item, cgit_query_sha1, "zip", 84 cgit_print_snapshot(item, cgit_query_sha1, "zip",
85 cgit_repo->url, cgit_query_name); 85 cgit_repo->url, cgit_query_name);
86 return; 86 return;
87 } 87 }
88 if (!strcmp(cgit_query_page, "blob")) { 88 if (!strcmp(cgit_query_page, "blob")) {
89 cgit_print_blob(item, cgit_query_sha1, cgit_query_path); 89 cgit_print_blob(item, cgit_query_sha1, cgit_query_path);
90 return; 90 return;
91 } 91 }
92 } 92 }
93 93
94 if (cgit_query_page && !strcmp(cgit_query_page, "log")) 94 if (cgit_query_page && !strcmp(cgit_query_page, "log"))
95 show_search = 1; 95 show_search = 1;
96 96
97 cgit_print_docstart(title, item); 97 cgit_print_docstart(title, item);
98 98
99 99
100 if (!cgit_query_page) { 100 if (!cgit_query_page) {
101 cgit_print_pageheader("summary", show_search); 101 cgit_print_pageheader("summary", show_search);
102 cgit_print_summary(); 102 cgit_print_summary();
103 cgit_print_docend(); 103 cgit_print_docend();
104 return; 104 return;
105 } 105 }
106 106
107 cgit_print_pageheader(cgit_query_page, show_search); 107 cgit_print_pageheader(cgit_query_page, show_search);
108 108
109 if (!strcmp(cgit_query_page, "log")) { 109 if (!strcmp(cgit_query_page, "log")) {
110 cgit_print_log(cgit_query_head, cgit_query_ofs, 100, 110 cgit_print_log(cgit_query_head, cgit_query_ofs,
111 cgit_query_search); 111 cgit_max_commit_count, cgit_query_search);
112 } else if (!strcmp(cgit_query_page, "tree")) { 112 } else if (!strcmp(cgit_query_page, "tree")) {
113 cgit_print_tree(cgit_query_sha1, cgit_query_path); 113 cgit_print_tree(cgit_query_sha1, cgit_query_path);
114 } else if (!strcmp(cgit_query_page, "commit")) { 114 } else if (!strcmp(cgit_query_page, "commit")) {
115 cgit_print_commit(cgit_query_sha1); 115 cgit_print_commit(cgit_query_sha1);
116 } else if (!strcmp(cgit_query_page, "view")) { 116 } else if (!strcmp(cgit_query_page, "view")) {
117 cgit_print_view(cgit_query_sha1, cgit_query_path); 117 cgit_print_view(cgit_query_sha1, cgit_query_path);
118 } else if (!strcmp(cgit_query_page, "diff")) { 118 } else if (!strcmp(cgit_query_page, "diff")) {
119 cgit_print_diff(cgit_query_sha1, cgit_query_sha2); 119 cgit_print_diff(cgit_query_sha1, cgit_query_sha2);
120 } else { 120 } else {
121 cgit_print_error("Invalid request"); 121 cgit_print_error("Invalid request");
122 } 122 }
123 cgit_print_docend(); 123 cgit_print_docend();
124} 124}
125 125
126static void cgit_fill_cache(struct cacheitem *item, int use_cache) 126static void cgit_fill_cache(struct cacheitem *item, int use_cache)
127{ 127{
128 static char buf[PATH_MAX]; 128 static char buf[PATH_MAX];
129 int stdout2; 129 int stdout2;
130 130
131 getcwd(buf, sizeof(buf)); 131 getcwd(buf, sizeof(buf));
132 item->st.st_mtime = time(NULL); 132 item->st.st_mtime = time(NULL);
133 133
134 if (use_cache) { 134 if (use_cache) {
135 stdout2 = chk_positive(dup(STDOUT_FILENO), 135 stdout2 = chk_positive(dup(STDOUT_FILENO),
136 "Preserving STDOUT"); 136 "Preserving STDOUT");
137 chk_zero(close(STDOUT_FILENO), "Closing STDOUT"); 137 chk_zero(close(STDOUT_FILENO), "Closing STDOUT");
138 chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)"); 138 chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)");
139 } 139 }
140 140
141 if (cgit_query_repo) 141 if (cgit_query_repo)
142 cgit_print_repo_page(item); 142 cgit_print_repo_page(item);
143 else 143 else
144 cgit_print_repolist(item); 144 cgit_print_repolist(item);
145 145
146 if (use_cache) { 146 if (use_cache) {
147 chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT"); 147 chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT");
148 chk_positive(dup2(stdout2, STDOUT_FILENO), 148 chk_positive(dup2(stdout2, STDOUT_FILENO),
149 "Restoring original STDOUT"); 149 "Restoring original STDOUT");
150 chk_zero(close(stdout2), "Closing temporary STDOUT"); 150 chk_zero(close(stdout2), "Closing temporary STDOUT");
151 } 151 }
152 152
153 chdir(buf); 153 chdir(buf);
154} 154}
155 155
156static void cgit_check_cache(struct cacheitem *item) 156static void cgit_check_cache(struct cacheitem *item)
157{ 157{
158 int i = 0; 158 int i = 0;
159 159
160 top: 160 top:
161 if (++i > cgit_max_lock_attempts) { 161 if (++i > cgit_max_lock_attempts) {
162 die("cgit_refresh_cache: unable to lock %s: %s", 162 die("cgit_refresh_cache: unable to lock %s: %s",
163 item->name, strerror(errno)); 163 item->name, strerror(errno));
164 } 164 }
165 if (!cache_exist(item)) { 165 if (!cache_exist(item)) {
166 if (!cache_lock(item)) { 166 if (!cache_lock(item)) {
167 sleep(1); 167 sleep(1);
168 goto top; 168 goto top;
169 } 169 }
170 if (!cache_exist(item)) { 170 if (!cache_exist(item)) {
171 cgit_fill_cache(item, 1); 171 cgit_fill_cache(item, 1);
172 cache_unlock(item); 172 cache_unlock(item);
173 } else { 173 } else {
174 cache_cancel_lock(item); 174 cache_cancel_lock(item);
175 } 175 }
176 } else if (cache_expired(item) && cache_lock(item)) { 176 } else if (cache_expired(item) && cache_lock(item)) {
177 if (cache_expired(item)) { 177 if (cache_expired(item)) {
178 cgit_fill_cache(item, 1); 178 cgit_fill_cache(item, 1);
179 cache_unlock(item); 179 cache_unlock(item);
180 } else { 180 } else {
181 cache_cancel_lock(item); 181 cache_cancel_lock(item);
182 } 182 }
183 } 183 }
184} 184}
185 185
186static void cgit_print_cache(struct cacheitem *item) 186static void cgit_print_cache(struct cacheitem *item)
187{ 187{
188 static char buf[4096]; 188 static char buf[4096];
189 ssize_t i; 189 ssize_t i;
190 190
191 int fd = open(item->name, O_RDONLY); 191 int fd = open(item->name, O_RDONLY);
192 if (fd<0) 192 if (fd<0)
193 die("Unable to open cached file %s", item->name); 193 die("Unable to open cached file %s", item->name);
194 194
195 while((i=read(fd, buf, sizeof(buf))) > 0) 195 while((i=read(fd, buf, sizeof(buf))) > 0)
196 write(STDOUT_FILENO, buf, i); 196 write(STDOUT_FILENO, buf, i);
197 197
198 close(fd); 198 close(fd);
199} 199}
200 200
201static void cgit_parse_args(int argc, const char **argv) 201static void cgit_parse_args(int argc, const char **argv)
202{ 202{
203 int i; 203 int i;
204 204
205 for (i = 1; i < argc; i++) { 205 for (i = 1; i < argc; i++) {
206 if (!strncmp(argv[i], "--cache=", 8)) { 206 if (!strncmp(argv[i], "--cache=", 8)) {
207 cgit_cache_root = xstrdup(argv[i]+8); 207 cgit_cache_root = xstrdup(argv[i]+8);
208 } 208 }
209 if (!strcmp(argv[i], "--nocache")) { 209 if (!strcmp(argv[i], "--nocache")) {
210 cgit_nocache = 1; 210 cgit_nocache = 1;
211 } 211 }
212 if (!strncmp(argv[i], "--query=", 8)) { 212 if (!strncmp(argv[i], "--query=", 8)) {
213 cgit_querystring = xstrdup(argv[i]+8); 213 cgit_querystring = xstrdup(argv[i]+8);
214 } 214 }
215 if (!strncmp(argv[i], "--repo=", 7)) { 215 if (!strncmp(argv[i], "--repo=", 7)) {
216 cgit_query_repo = xstrdup(argv[i]+7); 216 cgit_query_repo = xstrdup(argv[i]+7);
217 } 217 }
218 if (!strncmp(argv[i], "--page=", 7)) { 218 if (!strncmp(argv[i], "--page=", 7)) {
219 cgit_query_page = xstrdup(argv[i]+7); 219 cgit_query_page = xstrdup(argv[i]+7);
220 } 220 }
221 if (!strncmp(argv[i], "--head=", 7)) { 221 if (!strncmp(argv[i], "--head=", 7)) {
222 cgit_query_head = xstrdup(argv[i]+7); 222 cgit_query_head = xstrdup(argv[i]+7);
223 cgit_query_has_symref = 1; 223 cgit_query_has_symref = 1;
224 } 224 }
225 if (!strncmp(argv[i], "--sha1=", 7)) { 225 if (!strncmp(argv[i], "--sha1=", 7)) {
226 cgit_query_sha1 = xstrdup(argv[i]+7); 226 cgit_query_sha1 = xstrdup(argv[i]+7);
227 cgit_query_has_sha1 = 1; 227 cgit_query_has_sha1 = 1;
228 } 228 }
229 if (!strncmp(argv[i], "--ofs=", 6)) { 229 if (!strncmp(argv[i], "--ofs=", 6)) {
230 cgit_query_ofs = atoi(argv[i]+6); 230 cgit_query_ofs = atoi(argv[i]+6);
231 } 231 }
232 } 232 }
233} 233}
234 234
235int main(int argc, const char **argv) 235int main(int argc, const char **argv)
236{ 236{
237 struct cacheitem item; 237 struct cacheitem item;
238 238
239 htmlfd = STDOUT_FILENO; 239 htmlfd = STDOUT_FILENO;
240 item.st.st_mtime = time(NULL); 240 item.st.st_mtime = time(NULL);
241 cgit_repolist.length = 0; 241 cgit_repolist.length = 0;
242 cgit_repolist.count = 0; 242 cgit_repolist.count = 0;
243 cgit_repolist.repos = NULL; 243 cgit_repolist.repos = NULL;
244 244
245 cgit_read_config("/etc/cgitrc", cgit_global_config_cb); 245 cgit_read_config("/etc/cgitrc", cgit_global_config_cb);
246 if (getenv("QUERY_STRING")) 246 if (getenv("QUERY_STRING"))
247 cgit_querystring = xstrdup(getenv("QUERY_STRING")); 247 cgit_querystring = xstrdup(getenv("QUERY_STRING"));
248 cgit_parse_args(argc, argv); 248 cgit_parse_args(argc, argv);
249 cgit_parse_query(cgit_querystring, cgit_querystring_cb); 249 cgit_parse_query(cgit_querystring, cgit_querystring_cb);
250 if (!cgit_prepare_cache(&item)) 250 if (!cgit_prepare_cache(&item))
251 return 0; 251 return 0;
252 if (cgit_nocache) { 252 if (cgit_nocache) {
253 cgit_fill_cache(&item, 0); 253 cgit_fill_cache(&item, 0);
254 } else { 254 } else {
255 cgit_check_cache(&item); 255 cgit_check_cache(&item);
256 cgit_print_cache(&item); 256 cgit_print_cache(&item);
257 } 257 }
258 return 0; 258 return 0;
259} 259}
diff --git a/cgit.h b/cgit.h
index 43de375..46f3173 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,181 +1,182 @@
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
21typedef void (*configfn)(const char *name, const char *value); 21typedef void (*configfn)(const char *name, const char *value);
22typedef void (*filepair_fn)(struct diff_filepair *pair); 22typedef void (*filepair_fn)(struct diff_filepair *pair);
23typedef void (*linediff_fn)(char *line, int len); 23typedef void (*linediff_fn)(char *line, int len);
24 24
25struct cacheitem { 25struct cacheitem {
26 char *name; 26 char *name;
27 struct stat st; 27 struct stat st;
28 int ttl; 28 int ttl;
29 int fd; 29 int fd;
30}; 30};
31 31
32struct repoinfo { 32struct repoinfo {
33 char *url; 33 char *url;
34 char *name; 34 char *name;
35 char *path; 35 char *path;
36 char *desc; 36 char *desc;
37 char *owner; 37 char *owner;
38 char *module_link; 38 char *module_link;
39 int snapshots; 39 int snapshots;
40}; 40};
41 41
42struct repolist { 42struct repolist {
43 int length; 43 int length;
44 int count; 44 int count;
45 struct repoinfo *repos; 45 struct repoinfo *repos;
46}; 46};
47 47
48struct commitinfo { 48struct commitinfo {
49 struct commit *commit; 49 struct commit *commit;
50 char *author; 50 char *author;
51 char *author_email; 51 char *author_email;
52 unsigned long author_date; 52 unsigned long author_date;
53 char *committer; 53 char *committer;
54 char *committer_email; 54 char *committer_email;
55 unsigned long committer_date; 55 unsigned long committer_date;
56 char *subject; 56 char *subject;
57 char *msg; 57 char *msg;
58}; 58};
59 59
60struct taginfo { 60struct taginfo {
61 char *tagger; 61 char *tagger;
62 char *tagger_email; 62 char *tagger_email;
63 int tagger_date; 63 int tagger_date;
64 char *msg; 64 char *msg;
65}; 65};
66 66
67extern const char cgit_version[]; 67extern const char cgit_version[];
68 68
69extern struct repolist cgit_repolist; 69extern struct repolist cgit_repolist;
70extern struct repoinfo *cgit_repo; 70extern struct repoinfo *cgit_repo;
71 71
72extern char *cgit_root_title; 72extern char *cgit_root_title;
73extern char *cgit_css; 73extern char *cgit_css;
74extern char *cgit_logo; 74extern char *cgit_logo;
75extern char *cgit_logo_link; 75extern char *cgit_logo_link;
76extern char *cgit_module_link; 76extern char *cgit_module_link;
77extern char *cgit_virtual_root; 77extern char *cgit_virtual_root;
78extern char *cgit_cache_root; 78extern char *cgit_cache_root;
79 79
80extern int cgit_nocache; 80extern int cgit_nocache;
81extern int cgit_snapshots; 81extern int cgit_snapshots;
82extern int cgit_max_lock_attempts; 82extern int cgit_max_lock_attempts;
83extern int cgit_cache_root_ttl; 83extern int cgit_cache_root_ttl;
84extern int cgit_cache_repo_ttl; 84extern int cgit_cache_repo_ttl;
85extern int cgit_cache_dynamic_ttl; 85extern int cgit_cache_dynamic_ttl;
86extern int cgit_cache_static_ttl; 86extern int cgit_cache_static_ttl;
87extern int cgit_cache_max_create_time; 87extern int cgit_cache_max_create_time;
88 88
89extern int cgit_max_msg_len; 89extern int cgit_max_msg_len;
90extern int cgit_max_commit_count;
90 91
91extern char *cgit_repo_name; 92extern char *cgit_repo_name;
92extern char *cgit_repo_desc; 93extern char *cgit_repo_desc;
93extern char *cgit_repo_owner; 94extern char *cgit_repo_owner;
94 95
95extern int cgit_query_has_symref; 96extern int cgit_query_has_symref;
96extern int cgit_query_has_sha1; 97extern int cgit_query_has_sha1;
97 98
98extern char *cgit_querystring; 99extern char *cgit_querystring;
99extern char *cgit_query_repo; 100extern char *cgit_query_repo;
100extern char *cgit_query_page; 101extern char *cgit_query_page;
101extern char *cgit_query_search; 102extern char *cgit_query_search;
102extern char *cgit_query_head; 103extern char *cgit_query_head;
103extern char *cgit_query_sha1; 104extern char *cgit_query_sha1;
104extern char *cgit_query_sha2; 105extern char *cgit_query_sha2;
105extern char *cgit_query_path; 106extern char *cgit_query_path;
106extern char *cgit_query_name; 107extern char *cgit_query_name;
107extern int cgit_query_ofs; 108extern int cgit_query_ofs;
108 109
109extern int htmlfd; 110extern int htmlfd;
110 111
111extern void cgit_global_config_cb(const char *name, const char *value); 112extern void cgit_global_config_cb(const char *name, const char *value);
112extern void cgit_repo_config_cb(const char *name, const char *value); 113extern void cgit_repo_config_cb(const char *name, const char *value);
113extern void cgit_querystring_cb(const char *name, const char *value); 114extern void cgit_querystring_cb(const char *name, const char *value);
114 115
115extern int chk_zero(int result, char *msg); 116extern int chk_zero(int result, char *msg);
116extern int chk_positive(int result, char *msg); 117extern int chk_positive(int result, char *msg);
117 118
118extern int hextoint(char c); 119extern int hextoint(char c);
119 120
120extern void *cgit_free_commitinfo(struct commitinfo *info); 121extern void *cgit_free_commitinfo(struct commitinfo *info);
121 122
122extern int cgit_diff_files(const unsigned char *old_sha1, 123extern int cgit_diff_files(const unsigned char *old_sha1,
123 const unsigned char *new_sha1, 124 const unsigned char *new_sha1,
124 linediff_fn fn); 125 linediff_fn fn);
125 126
126extern void cgit_diff_tree(const unsigned char *old_sha1, 127extern void cgit_diff_tree(const unsigned char *old_sha1,
127 const unsigned char *new_sha1, 128 const unsigned char *new_sha1,
128 filepair_fn fn); 129 filepair_fn fn);
129 130
130extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 131extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
131 132
132extern char *fmt(const char *format,...); 133extern char *fmt(const char *format,...);
133 134
134extern void html(const char *txt); 135extern void html(const char *txt);
135extern void htmlf(const char *format,...); 136extern void htmlf(const char *format,...);
136extern void html_txt(char *txt); 137extern void html_txt(char *txt);
137extern void html_ntxt(int len, char *txt); 138extern void html_ntxt(int len, char *txt);
138extern void html_attr(char *txt); 139extern void html_attr(char *txt);
139extern void html_hidden(char *name, char *value); 140extern void html_hidden(char *name, char *value);
140extern void html_link_open(char *url, char *title, char *class); 141extern void html_link_open(char *url, char *title, char *class);
141extern void html_link_close(void); 142extern void html_link_close(void);
142extern void html_filemode(unsigned short mode); 143extern void html_filemode(unsigned short mode);
143 144
144extern int cgit_read_config(const char *filename, configfn fn); 145extern int cgit_read_config(const char *filename, configfn fn);
145extern int cgit_parse_query(char *txt, configfn fn); 146extern int cgit_parse_query(char *txt, configfn fn);
146extern struct commitinfo *cgit_parse_commit(struct commit *commit); 147extern struct commitinfo *cgit_parse_commit(struct commit *commit);
147extern struct taginfo *cgit_parse_tag(struct tag *tag); 148extern struct taginfo *cgit_parse_tag(struct tag *tag);
148 149
149extern char *cache_safe_filename(const char *unsafe); 150extern char *cache_safe_filename(const char *unsafe);
150extern int cache_lock(struct cacheitem *item); 151extern int cache_lock(struct cacheitem *item);
151extern int cache_unlock(struct cacheitem *item); 152extern int cache_unlock(struct cacheitem *item);
152extern int cache_cancel_lock(struct cacheitem *item); 153extern int cache_cancel_lock(struct cacheitem *item);
153extern int cache_exist(struct cacheitem *item); 154extern int cache_exist(struct cacheitem *item);
154extern int cache_expired(struct cacheitem *item); 155extern int cache_expired(struct cacheitem *item);
155 156
156extern char *cgit_repourl(const char *reponame); 157extern char *cgit_repourl(const char *reponame);
157extern char *cgit_pageurl(const char *reponame, const char *pagename, 158extern char *cgit_pageurl(const char *reponame, const char *pagename,
158 const char *query); 159 const char *query);
159 160
160extern void cgit_print_error(char *msg); 161extern void cgit_print_error(char *msg);
161extern void cgit_print_date(unsigned long secs); 162extern void cgit_print_date(unsigned long secs);
162extern void cgit_print_docstart(char *title, struct cacheitem *item); 163extern void cgit_print_docstart(char *title, struct cacheitem *item);
163extern void cgit_print_docend(); 164extern void cgit_print_docend();
164extern void cgit_print_pageheader(char *title, int show_search); 165extern void cgit_print_pageheader(char *title, int show_search);
165extern void cgit_print_snapshot_start(const char *mimetype, 166extern void cgit_print_snapshot_start(const char *mimetype,
166 const char *filename, 167 const char *filename,
167 struct cacheitem *item); 168 struct cacheitem *item);
168 169
169extern void cgit_print_repolist(struct cacheitem *item); 170extern void cgit_print_repolist(struct cacheitem *item);
170extern void cgit_print_summary(); 171extern void cgit_print_summary();
171extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep); 172extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep);
172extern void cgit_print_view(const char *hex, char *path); 173extern void cgit_print_view(const char *hex, char *path);
173extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); 174extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path);
174extern void cgit_print_tree(const char *hex, char *path); 175extern void cgit_print_tree(const char *hex, char *path);
175extern void cgit_print_commit(const char *hex); 176extern void cgit_print_commit(const char *hex);
176extern void cgit_print_diff(const char *old_hex, const char *new_hex); 177extern void cgit_print_diff(const char *old_hex, const char *new_hex);
177extern void cgit_print_snapshot(struct cacheitem *item, const char *hex, 178extern void cgit_print_snapshot(struct cacheitem *item, const char *hex,
178 const char *format, const char *prefix, 179 const char *format, const char *prefix,
179 const char *filename); 180 const char *filename);
180 181
181#endif /* CGIT_H */ 182#endif /* CGIT_H */
diff --git a/cgitrc b/cgitrc
index f217b39..019781e 100644
--- a/cgitrc
+++ b/cgitrc
@@ -1,89 +1,93 @@
1## 1##
2## cgitrc: template for /etc/cgitrc 2## cgitrc: template for /etc/cgitrc
3## 3##
4 4
5 5
6## Uncomment and set to 1 to deactivate caching of generated pages. Mostly 6## Uncomment and set to 1 to deactivate caching of generated pages. Mostly
7## usefull for testing. 7## usefull for testing.
8#nocache=0 8#nocache=0
9 9
10 10
11## Enable/disable snapshots by default. This can be overridden per repo 11## Enable/disable snapshots by default. This can be overridden per repo
12#snapshots=0 12#snapshots=0
13 13
14 14
15## Specify a root for virtual urls. This makes cgit generate urls like 15## Specify a root for virtual urls. This makes cgit generate urls like
16## 16##
17## http://localhost/git/repo/log/?id=master 17## http://localhost/git/repo/log/?id=master
18## 18##
19## instead of 19## instead of
20## 20##
21## http://localhost/cgit/cgit.cgi?r=repo&p=log&id=master 21## http://localhost/cgit/cgit.cgi?r=repo&p=log&id=master
22## 22##
23## For this to work with apache, rewrite rules must be added to httpd.conf, 23## For this to work with apache, rewrite rules must be added to httpd.conf,
24## possibly looking something like this: 24## possibly looking something like this:
25## 25##
26## RewriteRule ^/git/$ /cgit/cgit.cgi [L,QSA] 26## RewriteRule ^/git/$ /cgit/cgit.cgi [L,QSA]
27## RewriteRule ^/git/([^/]+)/$ /cgit/cgit.cgi?r=$1 [L,QSA] 27## RewriteRule ^/git/([^/]+)/$ /cgit/cgit.cgi?r=$1 [L,QSA]
28## RewriteRule ^/git/([^/]+)/([^/]+)/$ /cgit/cgit.cgi?r=$1&p=$2 [L,QSA] 28## RewriteRule ^/git/([^/]+)/([^/]+)/$ /cgit/cgit.cgi?r=$1&p=$2 [L,QSA]
29## 29##
30## This setting is disabled by default. 30## This setting is disabled by default.
31#virtual-root=/git 31#virtual-root=/git
32 32
33 33
34## Set the title printed on the root page 34## Set the title printed on the root page
35#root-title=Git repository browser 35#root-title=Git repository browser
36 36
37 37
38## Link to css file 38## Link to css file
39#css=/cgit/cgit.css 39#css=/cgit/cgit.css
40 40
41 41
42## Link to logo file 42## Link to logo file
43#logo=/cgit/git-logo.png 43#logo=/cgit/git-logo.png
44 44
45 45
46## Url loaded when clicking the logo 46## Url loaded when clicking the logo
47#logo-link=http://www.kernel.org/pub/software/scm/git/docs/ 47#logo-link=http://www.kernel.org/pub/software/scm/git/docs/
48 48
49 49
50## Url loaded when clicking a submodule link 50## Url loaded when clicking a submodule link
51#module-link=./?repo=%s&page=commit&id=%s 51#module-link=./?repo=%s&page=commit&id=%s
52 52
53 53
54## Number of chars shown of commit subject message (in log view) 54## Number of chars shown of commit subject message (in log view)
55#max-message-length=60 55#max-message-length=60
56 56
57 57
58## Number of commits per page in log view
59#max-commit-count=50
60
61
58## Root of cached output 62## Root of cached output
59#cache-root=/var/cache/cgit 63#cache-root=/var/cache/cgit
60 64
61 65
62## 66##
63## Time-To-Live settings: specifies how long (in minutes) different pages 67## Time-To-Live settings: specifies how long (in minutes) different pages
64## should be cached (0 for instant expiration, -1 for immortal pages) 68## should be cached (0 for instant expiration, -1 for immortal pages)
65## 69##
66 70
67## ttl for root page 71## ttl for root page
68#cache-root-ttl=5 72#cache-root-ttl=5
69 73
70## ttl for repo summary page 74## ttl for repo summary page
71#cache-repo-ttl=5 75#cache-repo-ttl=5
72 76
73## ttl for other dynamic pages 77## ttl for other dynamic pages
74#cache-dynamic-ttl=5 78#cache-dynamic-ttl=5
75 79
76## ttl for static pages (addressed by SHA-1) 80## ttl for static pages (addressed by SHA-1)
77#cache-static-ttl=-1 81#cache-static-ttl=-1
78 82
79 83
80 84
81## Example repository entry. Required values are repo.url and repo.path (each 85## Example repository entry. Required values are repo.url and repo.path (each
82## repository section must start with repo.url). 86## repository section must start with repo.url).
83#repo.url=cgit 87#repo.url=cgit
84#repo.name=cgit 88#repo.name=cgit
85#repo.desc=the caching cgi for git 89#repo.desc=the caching cgi for git
86#repo.path=/pub/git/cgit 90#repo.path=/pub/git/cgit
87#repo.owner=Lars Hjemli 91#repo.owner=Lars Hjemli
88 #repo.snapshots=1 # override a sitewide snapshot-setting 92 #repo.snapshots=1 # override a sitewide snapshot-setting
89 #repo.module-link=/git/%s/commit/?id=%s # override the standard module-link 93 #repo.module-link=/git/%s/commit/?id=%s # override the standard module-link
diff --git a/shared.c b/shared.c
index 801f68d..ffecac8 100644
--- a/shared.c
+++ b/shared.c
@@ -1,319 +1,322 @@
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;
13 13
14char *cgit_root_title = "Git repository browser"; 14char *cgit_root_title = "Git repository browser";
15char *cgit_css = "/cgit.css"; 15char *cgit_css = "/cgit.css";
16char *cgit_logo = "/git-logo.png"; 16char *cgit_logo = "/git-logo.png";
17char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/"; 17char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/";
18char *cgit_module_link = "./?repo=%s&page=commit&id=%s"; 18char *cgit_module_link = "./?repo=%s&page=commit&id=%s";
19char *cgit_virtual_root = NULL; 19char *cgit_virtual_root = NULL;
20 20
21char *cgit_cache_root = "/var/cache/cgit"; 21char *cgit_cache_root = "/var/cache/cgit";
22 22
23int cgit_nocache = 0; 23int cgit_nocache = 0;
24int cgit_snapshots = 0; 24int cgit_snapshots = 0;
25int cgit_max_lock_attempts = 5; 25int cgit_max_lock_attempts = 5;
26int cgit_cache_root_ttl = 5; 26int cgit_cache_root_ttl = 5;
27int cgit_cache_repo_ttl = 5; 27int cgit_cache_repo_ttl = 5;
28int cgit_cache_dynamic_ttl = 5; 28int cgit_cache_dynamic_ttl = 5;
29int cgit_cache_static_ttl = -1; 29int cgit_cache_static_ttl = -1;
30int cgit_cache_max_create_time = 5; 30int cgit_cache_max_create_time = 5;
31 31
32int cgit_max_msg_len = 60; 32int cgit_max_msg_len = 60;
33int cgit_max_commit_count = 50;
33 34
34char *cgit_repo_name = NULL; 35char *cgit_repo_name = NULL;
35char *cgit_repo_desc = NULL; 36char *cgit_repo_desc = NULL;
36char *cgit_repo_owner = NULL; 37char *cgit_repo_owner = NULL;
37 38
38int cgit_query_has_symref = 0; 39int cgit_query_has_symref = 0;
39int cgit_query_has_sha1 = 0; 40int cgit_query_has_sha1 = 0;
40 41
41char *cgit_querystring = NULL; 42char *cgit_querystring = NULL;
42char *cgit_query_repo = NULL; 43char *cgit_query_repo = NULL;
43char *cgit_query_page = NULL; 44char *cgit_query_page = NULL;
44char *cgit_query_head = NULL; 45char *cgit_query_head = NULL;
45char *cgit_query_search = NULL; 46char *cgit_query_search = NULL;
46char *cgit_query_sha1 = NULL; 47char *cgit_query_sha1 = NULL;
47char *cgit_query_sha2 = NULL; 48char *cgit_query_sha2 = NULL;
48char *cgit_query_path = NULL; 49char *cgit_query_path = NULL;
49char *cgit_query_name = NULL; 50char *cgit_query_name = NULL;
50int cgit_query_ofs = 0; 51int cgit_query_ofs = 0;
51 52
52int htmlfd = 0; 53int htmlfd = 0;
53 54
54int chk_zero(int result, char *msg) 55int chk_zero(int result, char *msg)
55{ 56{
56 if (result != 0) 57 if (result != 0)
57 die("%s: %s", msg, strerror(errno)); 58 die("%s: %s", msg, strerror(errno));
58 return result; 59 return result;
59} 60}
60 61
61int chk_positive(int result, char *msg) 62int chk_positive(int result, char *msg)
62{ 63{
63 if (result <= 0) 64 if (result <= 0)
64 die("%s: %s", msg, strerror(errno)); 65 die("%s: %s", msg, strerror(errno));
65 return result; 66 return result;
66} 67}
67 68
68struct repoinfo *add_repo(const char *url) 69struct repoinfo *add_repo(const char *url)
69{ 70{
70 struct repoinfo *ret; 71 struct repoinfo *ret;
71 72
72 if (++cgit_repolist.count > cgit_repolist.length) { 73 if (++cgit_repolist.count > cgit_repolist.length) {
73 if (cgit_repolist.length == 0) 74 if (cgit_repolist.length == 0)
74 cgit_repolist.length = 8; 75 cgit_repolist.length = 8;
75 else 76 else
76 cgit_repolist.length *= 2; 77 cgit_repolist.length *= 2;
77 cgit_repolist.repos = xrealloc(cgit_repolist.repos, 78 cgit_repolist.repos = xrealloc(cgit_repolist.repos,
78 cgit_repolist.length * 79 cgit_repolist.length *
79 sizeof(struct repoinfo)); 80 sizeof(struct repoinfo));
80 } 81 }
81 82
82 ret = &cgit_repolist.repos[cgit_repolist.count-1]; 83 ret = &cgit_repolist.repos[cgit_repolist.count-1];
83 ret->url = xstrdup(url); 84 ret->url = xstrdup(url);
84 ret->name = ret->url; 85 ret->name = ret->url;
85 ret->path = NULL; 86 ret->path = NULL;
86 ret->desc = NULL; 87 ret->desc = NULL;
87 ret->owner = NULL; 88 ret->owner = NULL;
88 ret->snapshots = cgit_snapshots; 89 ret->snapshots = cgit_snapshots;
89 ret->module_link = cgit_module_link; 90 ret->module_link = cgit_module_link;
90 return ret; 91 return ret;
91} 92}
92 93
93void cgit_global_config_cb(const char *name, const char *value) 94void cgit_global_config_cb(const char *name, const char *value)
94{ 95{
95 if (!strcmp(name, "root-title")) 96 if (!strcmp(name, "root-title"))
96 cgit_root_title = xstrdup(value); 97 cgit_root_title = xstrdup(value);
97 else if (!strcmp(name, "css")) 98 else if (!strcmp(name, "css"))
98 cgit_css = xstrdup(value); 99 cgit_css = xstrdup(value);
99 else if (!strcmp(name, "logo")) 100 else if (!strcmp(name, "logo"))
100 cgit_logo = xstrdup(value); 101 cgit_logo = xstrdup(value);
101 else if (!strcmp(name, "logo-link")) 102 else if (!strcmp(name, "logo-link"))
102 cgit_logo_link = xstrdup(value); 103 cgit_logo_link = xstrdup(value);
103 else if (!strcmp(name, "module-link")) 104 else if (!strcmp(name, "module-link"))
104 cgit_module_link = xstrdup(value); 105 cgit_module_link = xstrdup(value);
105 else if (!strcmp(name, "virtual-root")) 106 else if (!strcmp(name, "virtual-root"))
106 cgit_virtual_root = xstrdup(value); 107 cgit_virtual_root = xstrdup(value);
107 else if (!strcmp(name, "nocache")) 108 else if (!strcmp(name, "nocache"))
108 cgit_nocache = atoi(value); 109 cgit_nocache = atoi(value);
109 else if (!strcmp(name, "snapshots")) 110 else if (!strcmp(name, "snapshots"))
110 cgit_snapshots = atoi(value); 111 cgit_snapshots = atoi(value);
111 else if (!strcmp(name, "cache-root")) 112 else if (!strcmp(name, "cache-root"))
112 cgit_cache_root = xstrdup(value); 113 cgit_cache_root = xstrdup(value);
113 else if (!strcmp(name, "cache-root-ttl")) 114 else if (!strcmp(name, "cache-root-ttl"))
114 cgit_cache_root_ttl = atoi(value); 115 cgit_cache_root_ttl = atoi(value);
115 else if (!strcmp(name, "cache-repo-ttl")) 116 else if (!strcmp(name, "cache-repo-ttl"))
116 cgit_cache_repo_ttl = atoi(value); 117 cgit_cache_repo_ttl = atoi(value);
117 else if (!strcmp(name, "cache-static-ttl")) 118 else if (!strcmp(name, "cache-static-ttl"))
118 cgit_cache_static_ttl = atoi(value); 119 cgit_cache_static_ttl = atoi(value);
119 else if (!strcmp(name, "cache-dynamic-ttl")) 120 else if (!strcmp(name, "cache-dynamic-ttl"))
120 cgit_cache_dynamic_ttl = atoi(value); 121 cgit_cache_dynamic_ttl = atoi(value);
121 else if (!strcmp(name, "max-message-length")) 122 else if (!strcmp(name, "max-message-length"))
122 cgit_max_msg_len = atoi(value); 123 cgit_max_msg_len = atoi(value);
124 else if (!strcmp(name, "max-commit-count"))
125 cgit_max_commit_count = atoi(value);
123 else if (!strcmp(name, "repo.url")) 126 else if (!strcmp(name, "repo.url"))
124 cgit_repo = add_repo(value); 127 cgit_repo = add_repo(value);
125 else if (!strcmp(name, "repo.name")) 128 else if (!strcmp(name, "repo.name"))
126 cgit_repo->name = xstrdup(value); 129 cgit_repo->name = xstrdup(value);
127 else if (cgit_repo && !strcmp(name, "repo.path")) 130 else if (cgit_repo && !strcmp(name, "repo.path"))
128 cgit_repo->path = xstrdup(value); 131 cgit_repo->path = xstrdup(value);
129 else if (cgit_repo && !strcmp(name, "repo.desc")) 132 else if (cgit_repo && !strcmp(name, "repo.desc"))
130 cgit_repo->desc = xstrdup(value); 133 cgit_repo->desc = xstrdup(value);
131 else if (cgit_repo && !strcmp(name, "repo.owner")) 134 else if (cgit_repo && !strcmp(name, "repo.owner"))
132 cgit_repo->owner = xstrdup(value); 135 cgit_repo->owner = xstrdup(value);
133 else if (cgit_repo && !strcmp(name, "repo.snapshots")) 136 else if (cgit_repo && !strcmp(name, "repo.snapshots"))
134 cgit_repo->snapshots = atoi(value); 137 cgit_repo->snapshots = atoi(value);
135 else if (cgit_repo && !strcmp(name, "repo.module-link")) 138 else if (cgit_repo && !strcmp(name, "repo.module-link"))
136 cgit_repo->module_link= xstrdup(value); 139 cgit_repo->module_link= xstrdup(value);
137} 140}
138 141
139void cgit_repo_config_cb(const char *name, const char *value) 142void cgit_repo_config_cb(const char *name, const char *value)
140{ 143{
141 if (!strcmp(name, "name")) 144 if (!strcmp(name, "name"))
142 cgit_repo_name = xstrdup(value); 145 cgit_repo_name = xstrdup(value);
143 else if (!strcmp(name, "desc")) 146 else if (!strcmp(name, "desc"))
144 cgit_repo_desc = xstrdup(value); 147 cgit_repo_desc = xstrdup(value);
145 else if (!strcmp(name, "owner")) 148 else if (!strcmp(name, "owner"))
146 cgit_repo_owner = xstrdup(value); 149 cgit_repo_owner = xstrdup(value);
147} 150}
148 151
149void cgit_querystring_cb(const char *name, const char *value) 152void cgit_querystring_cb(const char *name, const char *value)
150{ 153{
151 if (!strcmp(name,"r")) { 154 if (!strcmp(name,"r")) {
152 cgit_query_repo = xstrdup(value); 155 cgit_query_repo = xstrdup(value);
153 } else if (!strcmp(name, "p")) { 156 } else if (!strcmp(name, "p")) {
154 cgit_query_page = xstrdup(value); 157 cgit_query_page = xstrdup(value);
155 } else if (!strcmp(name, "q")) { 158 } else if (!strcmp(name, "q")) {
156 cgit_query_search = xstrdup(value); 159 cgit_query_search = xstrdup(value);
157 } else if (!strcmp(name, "h")) { 160 } else if (!strcmp(name, "h")) {
158 cgit_query_head = xstrdup(value); 161 cgit_query_head = xstrdup(value);
159 cgit_query_has_symref = 1; 162 cgit_query_has_symref = 1;
160 } else if (!strcmp(name, "id")) { 163 } else if (!strcmp(name, "id")) {
161 cgit_query_sha1 = xstrdup(value); 164 cgit_query_sha1 = xstrdup(value);
162 cgit_query_has_sha1 = 1; 165 cgit_query_has_sha1 = 1;
163 } else if (!strcmp(name, "id2")) { 166 } else if (!strcmp(name, "id2")) {
164 cgit_query_sha2 = xstrdup(value); 167 cgit_query_sha2 = xstrdup(value);
165 cgit_query_has_sha1 = 1; 168 cgit_query_has_sha1 = 1;
166 } else if (!strcmp(name, "ofs")) { 169 } else if (!strcmp(name, "ofs")) {
167 cgit_query_ofs = atoi(value); 170 cgit_query_ofs = atoi(value);
168 } else if (!strcmp(name, "path")) { 171 } else if (!strcmp(name, "path")) {
169 cgit_query_path = xstrdup(value); 172 cgit_query_path = xstrdup(value);
170 } else if (!strcmp(name, "name")) { 173 } else if (!strcmp(name, "name")) {
171 cgit_query_name = xstrdup(value); 174 cgit_query_name = xstrdup(value);
172 } 175 }
173} 176}
174 177
175void *cgit_free_commitinfo(struct commitinfo *info) 178void *cgit_free_commitinfo(struct commitinfo *info)
176{ 179{
177 free(info->author); 180 free(info->author);
178 free(info->author_email); 181 free(info->author_email);
179 free(info->committer); 182 free(info->committer);
180 free(info->committer_email); 183 free(info->committer_email);
181 free(info->subject); 184 free(info->subject);
182 free(info); 185 free(info);
183 return NULL; 186 return NULL;
184} 187}
185 188
186int hextoint(char c) 189int hextoint(char c)
187{ 190{
188 if (c >= 'a' && c <= 'f') 191 if (c >= 'a' && c <= 'f')
189 return 10 + c - 'a'; 192 return 10 + c - 'a';
190 else if (c >= 'A' && c <= 'F') 193 else if (c >= 'A' && c <= 'F')
191 return 10 + c - 'A'; 194 return 10 + c - 'A';
192 else if (c >= '0' && c <= '9') 195 else if (c >= '0' && c <= '9')
193 return c - '0'; 196 return c - '0';
194 else 197 else
195 return -1; 198 return -1;
196} 199}
197 200
198void cgit_diff_tree_cb(struct diff_queue_struct *q, 201void cgit_diff_tree_cb(struct diff_queue_struct *q,
199 struct diff_options *options, void *data) 202 struct diff_options *options, void *data)
200{ 203{
201 int i; 204 int i;
202 205
203 for (i = 0; i < q->nr; i++) { 206 for (i = 0; i < q->nr; i++) {
204 if (q->queue[i]->status == 'U') 207 if (q->queue[i]->status == 'U')
205 continue; 208 continue;
206 ((filepair_fn)data)(q->queue[i]); 209 ((filepair_fn)data)(q->queue[i]);
207 } 210 }
208} 211}
209 212
210static int load_mmfile(mmfile_t *file, const unsigned char *sha1) 213static int load_mmfile(mmfile_t *file, const unsigned char *sha1)
211{ 214{
212 enum object_type type; 215 enum object_type type;
213 216
214 if (is_null_sha1(sha1)) { 217 if (is_null_sha1(sha1)) {
215 file->ptr = (char *)""; 218 file->ptr = (char *)"";
216 file->size = 0; 219 file->size = 0;
217 } else { 220 } else {
218 file->ptr = read_sha1_file(sha1, &type, &file->size); 221 file->ptr = read_sha1_file(sha1, &type, &file->size);
219 } 222 }
220 return 1; 223 return 1;
221} 224}
222 225
223/* 226/*
224 * Receive diff-buffers from xdiff and concatenate them as 227 * Receive diff-buffers from xdiff and concatenate them as
225 * needed across multiple callbacks. 228 * needed across multiple callbacks.
226 * 229 *
227 * This is basically a copy of xdiff-interface.c/xdiff_outf(), 230 * This is basically a copy of xdiff-interface.c/xdiff_outf(),
228 * ripped from git and modified to use globals instead of 231 * ripped from git and modified to use globals instead of
229 * a special callback-struct. 232 * a special callback-struct.
230 */ 233 */
231char *diffbuf = NULL; 234char *diffbuf = NULL;
232int buflen = 0; 235int buflen = 0;
233 236
234int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf) 237int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)
235{ 238{
236 int i; 239 int i;
237 240
238 for (i = 0; i < nbuf; i++) { 241 for (i = 0; i < nbuf; i++) {
239 if (mb[i].ptr[mb[i].size-1] != '\n') { 242 if (mb[i].ptr[mb[i].size-1] != '\n') {
240 /* Incomplete line */ 243 /* Incomplete line */
241 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 244 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
242 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 245 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
243 buflen += mb[i].size; 246 buflen += mb[i].size;
244 continue; 247 continue;
245 } 248 }
246 249
247 /* we have a complete line */ 250 /* we have a complete line */
248 if (!diffbuf) { 251 if (!diffbuf) {
249 ((linediff_fn)priv)(mb[i].ptr, mb[i].size); 252 ((linediff_fn)priv)(mb[i].ptr, mb[i].size);
250 continue; 253 continue;
251 } 254 }
252 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 255 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
253 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 256 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
254 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size); 257 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size);
255 free(diffbuf); 258 free(diffbuf);
256 diffbuf = NULL; 259 diffbuf = NULL;
257 buflen = 0; 260 buflen = 0;
258 } 261 }
259 if (diffbuf) { 262 if (diffbuf) {
260 ((linediff_fn)priv)(diffbuf, buflen); 263 ((linediff_fn)priv)(diffbuf, buflen);
261 free(diffbuf); 264 free(diffbuf);
262 diffbuf = NULL; 265 diffbuf = NULL;
263 buflen = 0; 266 buflen = 0;
264 } 267 }
265 return 0; 268 return 0;
266} 269}
267 270
268int cgit_diff_files(const unsigned char *old_sha1, 271int cgit_diff_files(const unsigned char *old_sha1,
269 const unsigned char *new_sha1, 272 const unsigned char *new_sha1,
270 linediff_fn fn) 273 linediff_fn fn)
271{ 274{
272 mmfile_t file1, file2; 275 mmfile_t file1, file2;
273 xpparam_t diff_params; 276 xpparam_t diff_params;
274 xdemitconf_t emit_params; 277 xdemitconf_t emit_params;
275 xdemitcb_t emit_cb; 278 xdemitcb_t emit_cb;
276 279
277 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1)) 280 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1))
278 return 1; 281 return 1;
279 282
280 diff_params.flags = XDF_NEED_MINIMAL; 283 diff_params.flags = XDF_NEED_MINIMAL;
281 emit_params.ctxlen = 3; 284 emit_params.ctxlen = 3;
282 emit_params.flags = XDL_EMIT_FUNCNAMES; 285 emit_params.flags = XDL_EMIT_FUNCNAMES;
283 emit_cb.outf = filediff_cb; 286 emit_cb.outf = filediff_cb;
284 emit_cb.priv = fn; 287 emit_cb.priv = fn;
285 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); 288 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb);
286 return 0; 289 return 0;
287} 290}
288 291
289void cgit_diff_tree(const unsigned char *old_sha1, 292void cgit_diff_tree(const unsigned char *old_sha1,
290 const unsigned char *new_sha1, 293 const unsigned char *new_sha1,
291 filepair_fn fn) 294 filepair_fn fn)
292{ 295{
293 struct diff_options opt; 296 struct diff_options opt;
294 int ret; 297 int ret;
295 298
296 diff_setup(&opt); 299 diff_setup(&opt);
297 opt.output_format = DIFF_FORMAT_CALLBACK; 300 opt.output_format = DIFF_FORMAT_CALLBACK;
298 opt.detect_rename = 1; 301 opt.detect_rename = 1;
299 opt.recursive = 1; 302 opt.recursive = 1;
300 opt.format_callback = cgit_diff_tree_cb; 303 opt.format_callback = cgit_diff_tree_cb;
301 opt.format_callback_data = fn; 304 opt.format_callback_data = fn;
302 diff_setup_done(&opt); 305 diff_setup_done(&opt);
303 306
304 if (old_sha1) 307 if (old_sha1)
305 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt); 308 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt);
306 else 309 else
307 ret = diff_root_tree_sha1(new_sha1, "", &opt); 310 ret = diff_root_tree_sha1(new_sha1, "", &opt);
308 diffcore_std(&opt); 311 diffcore_std(&opt);
309 diff_flush(&opt); 312 diff_flush(&opt);
310} 313}
311 314
312void cgit_diff_commit(struct commit *commit, filepair_fn fn) 315void cgit_diff_commit(struct commit *commit, filepair_fn fn)
313{ 316{
314 unsigned char *old_sha1 = NULL; 317 unsigned char *old_sha1 = NULL;
315 318
316 if (commit->parents) 319 if (commit->parents)
317 old_sha1 = commit->parents->item->object.sha1; 320 old_sha1 = commit->parents->item->object.sha1;
318 cgit_diff_tree(old_sha1, commit->object.sha1, fn); 321 cgit_diff_tree(old_sha1, commit->object.sha1, fn);
319} 322}