summaryrefslogtreecommitdiffabout
path: root/cgit.c
authorLars Hjemli <hjemli@gmail.com>2009-07-31 14:55:27 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2009-07-31 15:41:21 (UTC)
commit46b7abed99e957008c01c02cf612aa526ba92f04 (patch) (unidiff)
tree2cdbfe5281c2ffa645def488d53db0a8b82842f4 /cgit.c
parent18dfbdc099c1398016427b6fa7f1a1facb363998 (diff)
downloadcgit-46b7abed99e957008c01c02cf612aa526ba92f04.zip
cgit-46b7abed99e957008c01c02cf612aa526ba92f04.tar.gz
cgit-46b7abed99e957008c01c02cf612aa526ba92f04.tar.bz2
ui-tree: add support for source-filter option
This new option is used to specify an external command which will be executed when displaying blob content in the tree view. Blob content will be written to STDIN of the filter and STDOUT from the filter will be included verbatim in the html output from cgit. The file name of the blob will be passed as the only argument to the filter command. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (limited to 'cgit.c') (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/cgit.c b/cgit.c
index 779a464..eb7b45d 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,513 +1,515 @@
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#include "cache.h" 10#include "cache.h"
11#include "cmd.h" 11#include "cmd.h"
12#include "configfile.h" 12#include "configfile.h"
13#include "html.h" 13#include "html.h"
14#include "ui-shared.h" 14#include "ui-shared.h"
15#include "ui-stats.h" 15#include "ui-stats.h"
16#include "scan-tree.h" 16#include "scan-tree.h"
17 17
18const char *cgit_version = CGIT_VERSION; 18const char *cgit_version = CGIT_VERSION;
19 19
20struct cgit_filter *new_filter(const char *cmd, int extra_args) 20struct cgit_filter *new_filter(const char *cmd, int extra_args)
21{ 21{
22 struct cgit_filter *f; 22 struct cgit_filter *f;
23 23
24 if (!cmd) 24 if (!cmd)
25 return NULL; 25 return NULL;
26 26
27 f = xmalloc(sizeof(struct cgit_filter)); 27 f = xmalloc(sizeof(struct cgit_filter));
28 f->cmd = xstrdup(cmd); 28 f->cmd = xstrdup(cmd);
29 f->argv = xmalloc((2 + extra_args) * sizeof(char *)); 29 f->argv = xmalloc((2 + extra_args) * sizeof(char *));
30 f->argv[0] = f->cmd; 30 f->argv[0] = f->cmd;
31 f->argv[1] = NULL; 31 f->argv[1] = NULL;
32 return f; 32 return f;
33} 33}
34 34
35void config_cb(const char *name, const char *value) 35void config_cb(const char *name, const char *value)
36{ 36{
37 if (!strcmp(name, "root-title")) 37 if (!strcmp(name, "root-title"))
38 ctx.cfg.root_title = xstrdup(value); 38 ctx.cfg.root_title = xstrdup(value);
39 else if (!strcmp(name, "root-desc")) 39 else if (!strcmp(name, "root-desc"))
40 ctx.cfg.root_desc = xstrdup(value); 40 ctx.cfg.root_desc = xstrdup(value);
41 else if (!strcmp(name, "root-readme")) 41 else if (!strcmp(name, "root-readme"))
42 ctx.cfg.root_readme = xstrdup(value); 42 ctx.cfg.root_readme = xstrdup(value);
43 else if (!strcmp(name, "css")) 43 else if (!strcmp(name, "css"))
44 ctx.cfg.css = xstrdup(value); 44 ctx.cfg.css = xstrdup(value);
45 else if (!strcmp(name, "favicon")) 45 else if (!strcmp(name, "favicon"))
46 ctx.cfg.favicon = xstrdup(value); 46 ctx.cfg.favicon = xstrdup(value);
47 else if (!strcmp(name, "footer")) 47 else if (!strcmp(name, "footer"))
48 ctx.cfg.footer = xstrdup(value); 48 ctx.cfg.footer = xstrdup(value);
49 else if (!strcmp(name, "head-include")) 49 else if (!strcmp(name, "head-include"))
50 ctx.cfg.head_include = xstrdup(value); 50 ctx.cfg.head_include = xstrdup(value);
51 else if (!strcmp(name, "header")) 51 else if (!strcmp(name, "header"))
52 ctx.cfg.header = xstrdup(value); 52 ctx.cfg.header = xstrdup(value);
53 else if (!strcmp(name, "logo")) 53 else if (!strcmp(name, "logo"))
54 ctx.cfg.logo = xstrdup(value); 54 ctx.cfg.logo = xstrdup(value);
55 else if (!strcmp(name, "index-header")) 55 else if (!strcmp(name, "index-header"))
56 ctx.cfg.index_header = xstrdup(value); 56 ctx.cfg.index_header = xstrdup(value);
57 else if (!strcmp(name, "index-info")) 57 else if (!strcmp(name, "index-info"))
58 ctx.cfg.index_info = xstrdup(value); 58 ctx.cfg.index_info = xstrdup(value);
59 else if (!strcmp(name, "logo-link")) 59 else if (!strcmp(name, "logo-link"))
60 ctx.cfg.logo_link = xstrdup(value); 60 ctx.cfg.logo_link = xstrdup(value);
61 else if (!strcmp(name, "module-link")) 61 else if (!strcmp(name, "module-link"))
62 ctx.cfg.module_link = xstrdup(value); 62 ctx.cfg.module_link = xstrdup(value);
63 else if (!strcmp(name, "virtual-root")) { 63 else if (!strcmp(name, "virtual-root")) {
64 ctx.cfg.virtual_root = trim_end(value, '/'); 64 ctx.cfg.virtual_root = trim_end(value, '/');
65 if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) 65 if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
66 ctx.cfg.virtual_root = ""; 66 ctx.cfg.virtual_root = "";
67 } else if (!strcmp(name, "nocache")) 67 } else if (!strcmp(name, "nocache"))
68 ctx.cfg.nocache = atoi(value); 68 ctx.cfg.nocache = atoi(value);
69 else if (!strcmp(name, "noheader")) 69 else if (!strcmp(name, "noheader"))
70 ctx.cfg.noheader = atoi(value); 70 ctx.cfg.noheader = atoi(value);
71 else if (!strcmp(name, "snapshots")) 71 else if (!strcmp(name, "snapshots"))
72 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); 72 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
73 else if (!strcmp(name, "enable-index-links")) 73 else if (!strcmp(name, "enable-index-links"))
74 ctx.cfg.enable_index_links = atoi(value); 74 ctx.cfg.enable_index_links = atoi(value);
75 else if (!strcmp(name, "enable-log-filecount")) 75 else if (!strcmp(name, "enable-log-filecount"))
76 ctx.cfg.enable_log_filecount = atoi(value); 76 ctx.cfg.enable_log_filecount = atoi(value);
77 else if (!strcmp(name, "enable-log-linecount")) 77 else if (!strcmp(name, "enable-log-linecount"))
78 ctx.cfg.enable_log_linecount = atoi(value); 78 ctx.cfg.enable_log_linecount = atoi(value);
79 else if (!strcmp(name, "max-stats")) 79 else if (!strcmp(name, "max-stats"))
80 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); 80 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL);
81 else if (!strcmp(name, "cache-size")) 81 else if (!strcmp(name, "cache-size"))
82 ctx.cfg.cache_size = atoi(value); 82 ctx.cfg.cache_size = atoi(value);
83 else if (!strcmp(name, "cache-root")) 83 else if (!strcmp(name, "cache-root"))
84 ctx.cfg.cache_root = xstrdup(value); 84 ctx.cfg.cache_root = xstrdup(value);
85 else if (!strcmp(name, "cache-root-ttl")) 85 else if (!strcmp(name, "cache-root-ttl"))
86 ctx.cfg.cache_root_ttl = atoi(value); 86 ctx.cfg.cache_root_ttl = atoi(value);
87 else if (!strcmp(name, "cache-repo-ttl")) 87 else if (!strcmp(name, "cache-repo-ttl"))
88 ctx.cfg.cache_repo_ttl = atoi(value); 88 ctx.cfg.cache_repo_ttl = atoi(value);
89 else if (!strcmp(name, "cache-static-ttl")) 89 else if (!strcmp(name, "cache-static-ttl"))
90 ctx.cfg.cache_static_ttl = atoi(value); 90 ctx.cfg.cache_static_ttl = atoi(value);
91 else if (!strcmp(name, "cache-dynamic-ttl")) 91 else if (!strcmp(name, "cache-dynamic-ttl"))
92 ctx.cfg.cache_dynamic_ttl = atoi(value); 92 ctx.cfg.cache_dynamic_ttl = atoi(value);
93 else if (!strcmp(name, "embedded")) 93 else if (!strcmp(name, "embedded"))
94 ctx.cfg.embedded = atoi(value); 94 ctx.cfg.embedded = atoi(value);
95 else if (!strcmp(name, "max-message-length")) 95 else if (!strcmp(name, "max-message-length"))
96 ctx.cfg.max_msg_len = atoi(value); 96 ctx.cfg.max_msg_len = atoi(value);
97 else if (!strcmp(name, "max-repodesc-length")) 97 else if (!strcmp(name, "max-repodesc-length"))
98 ctx.cfg.max_repodesc_len = atoi(value); 98 ctx.cfg.max_repodesc_len = atoi(value);
99 else if (!strcmp(name, "max-repo-count")) 99 else if (!strcmp(name, "max-repo-count"))
100 ctx.cfg.max_repo_count = atoi(value); 100 ctx.cfg.max_repo_count = atoi(value);
101 else if (!strcmp(name, "max-commit-count")) 101 else if (!strcmp(name, "max-commit-count"))
102 ctx.cfg.max_commit_count = atoi(value); 102 ctx.cfg.max_commit_count = atoi(value);
103 else if (!strcmp(name, "source-filter"))
104 ctx.cfg.source_filter = new_filter(value, 1);
103 else if (!strcmp(name, "summary-log")) 105 else if (!strcmp(name, "summary-log"))
104 ctx.cfg.summary_log = atoi(value); 106 ctx.cfg.summary_log = atoi(value);
105 else if (!strcmp(name, "summary-branches")) 107 else if (!strcmp(name, "summary-branches"))
106 ctx.cfg.summary_branches = atoi(value); 108 ctx.cfg.summary_branches = atoi(value);
107 else if (!strcmp(name, "summary-tags")) 109 else if (!strcmp(name, "summary-tags"))
108 ctx.cfg.summary_tags = atoi(value); 110 ctx.cfg.summary_tags = atoi(value);
109 else if (!strcmp(name, "agefile")) 111 else if (!strcmp(name, "agefile"))
110 ctx.cfg.agefile = xstrdup(value); 112 ctx.cfg.agefile = xstrdup(value);
111 else if (!strcmp(name, "renamelimit")) 113 else if (!strcmp(name, "renamelimit"))
112 ctx.cfg.renamelimit = atoi(value); 114 ctx.cfg.renamelimit = atoi(value);
113 else if (!strcmp(name, "robots")) 115 else if (!strcmp(name, "robots"))
114 ctx.cfg.robots = xstrdup(value); 116 ctx.cfg.robots = xstrdup(value);
115 else if (!strcmp(name, "clone-prefix")) 117 else if (!strcmp(name, "clone-prefix"))
116 ctx.cfg.clone_prefix = xstrdup(value); 118 ctx.cfg.clone_prefix = xstrdup(value);
117 else if (!strcmp(name, "local-time")) 119 else if (!strcmp(name, "local-time"))
118 ctx.cfg.local_time = atoi(value); 120 ctx.cfg.local_time = atoi(value);
119 else if (!strcmp(name, "repo.group")) 121 else if (!strcmp(name, "repo.group"))
120 ctx.cfg.repo_group = xstrdup(value); 122 ctx.cfg.repo_group = xstrdup(value);
121 else if (!strcmp(name, "repo.url")) 123 else if (!strcmp(name, "repo.url"))
122 ctx.repo = cgit_add_repo(value); 124 ctx.repo = cgit_add_repo(value);
123 else if (!strcmp(name, "repo.name")) 125 else if (!strcmp(name, "repo.name"))
124 ctx.repo->name = xstrdup(value); 126 ctx.repo->name = xstrdup(value);
125 else if (ctx.repo && !strcmp(name, "repo.path")) 127 else if (ctx.repo && !strcmp(name, "repo.path"))
126 ctx.repo->path = trim_end(value, '/'); 128 ctx.repo->path = trim_end(value, '/');
127 else if (ctx.repo && !strcmp(name, "repo.clone-url")) 129 else if (ctx.repo && !strcmp(name, "repo.clone-url"))
128 ctx.repo->clone_url = xstrdup(value); 130 ctx.repo->clone_url = xstrdup(value);
129 else if (ctx.repo && !strcmp(name, "repo.desc")) 131 else if (ctx.repo && !strcmp(name, "repo.desc"))
130 ctx.repo->desc = xstrdup(value); 132 ctx.repo->desc = xstrdup(value);
131 else if (ctx.repo && !strcmp(name, "repo.owner")) 133 else if (ctx.repo && !strcmp(name, "repo.owner"))
132 ctx.repo->owner = xstrdup(value); 134 ctx.repo->owner = xstrdup(value);
133 else if (ctx.repo && !strcmp(name, "repo.defbranch")) 135 else if (ctx.repo && !strcmp(name, "repo.defbranch"))
134 ctx.repo->defbranch = xstrdup(value); 136 ctx.repo->defbranch = xstrdup(value);
135 else if (ctx.repo && !strcmp(name, "repo.snapshots")) 137 else if (ctx.repo && !strcmp(name, "repo.snapshots"))
136 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ 138 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
137 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) 139 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount"))
138 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 140 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
139 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) 141 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount"))
140 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 142 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
141 else if (ctx.repo && !strcmp(name, "repo.max-stats")) 143 else if (ctx.repo && !strcmp(name, "repo.max-stats"))
142 ctx.repo->max_stats = cgit_find_stats_period(value, NULL); 144 ctx.repo->max_stats = cgit_find_stats_period(value, NULL);
143 else if (ctx.repo && !strcmp(name, "repo.module-link")) 145 else if (ctx.repo && !strcmp(name, "repo.module-link"))
144 ctx.repo->module_link= xstrdup(value); 146 ctx.repo->module_link= xstrdup(value);
145 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { 147 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
146 if (*value == '/') 148 if (*value == '/')
147 ctx.repo->readme = xstrdup(value); 149 ctx.repo->readme = xstrdup(value);
148 else 150 else
149 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); 151 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value));
150 } else if (!strcmp(name, "include")) 152 } else if (!strcmp(name, "include"))
151 parse_configfile(value, config_cb); 153 parse_configfile(value, config_cb);
152} 154}
153 155
154static void querystring_cb(const char *name, const char *value) 156static void querystring_cb(const char *name, const char *value)
155{ 157{
156 if (!strcmp(name,"r")) { 158 if (!strcmp(name,"r")) {
157 ctx.qry.repo = xstrdup(value); 159 ctx.qry.repo = xstrdup(value);
158 ctx.repo = cgit_get_repoinfo(value); 160 ctx.repo = cgit_get_repoinfo(value);
159 } else if (!strcmp(name, "p")) { 161 } else if (!strcmp(name, "p")) {
160 ctx.qry.page = xstrdup(value); 162 ctx.qry.page = xstrdup(value);
161 } else if (!strcmp(name, "url")) { 163 } else if (!strcmp(name, "url")) {
162 ctx.qry.url = xstrdup(value); 164 ctx.qry.url = xstrdup(value);
163 cgit_parse_url(value); 165 cgit_parse_url(value);
164 } else if (!strcmp(name, "qt")) { 166 } else if (!strcmp(name, "qt")) {
165 ctx.qry.grep = xstrdup(value); 167 ctx.qry.grep = xstrdup(value);
166 } else if (!strcmp(name, "q")) { 168 } else if (!strcmp(name, "q")) {
167 ctx.qry.search = xstrdup(value); 169 ctx.qry.search = xstrdup(value);
168 } else if (!strcmp(name, "h")) { 170 } else if (!strcmp(name, "h")) {
169 ctx.qry.head = xstrdup(value); 171 ctx.qry.head = xstrdup(value);
170 ctx.qry.has_symref = 1; 172 ctx.qry.has_symref = 1;
171 } else if (!strcmp(name, "id")) { 173 } else if (!strcmp(name, "id")) {
172 ctx.qry.sha1 = xstrdup(value); 174 ctx.qry.sha1 = xstrdup(value);
173 ctx.qry.has_sha1 = 1; 175 ctx.qry.has_sha1 = 1;
174 } else if (!strcmp(name, "id2")) { 176 } else if (!strcmp(name, "id2")) {
175 ctx.qry.sha2 = xstrdup(value); 177 ctx.qry.sha2 = xstrdup(value);
176 ctx.qry.has_sha1 = 1; 178 ctx.qry.has_sha1 = 1;
177 } else if (!strcmp(name, "ofs")) { 179 } else if (!strcmp(name, "ofs")) {
178 ctx.qry.ofs = atoi(value); 180 ctx.qry.ofs = atoi(value);
179 } else if (!strcmp(name, "path")) { 181 } else if (!strcmp(name, "path")) {
180 ctx.qry.path = trim_end(value, '/'); 182 ctx.qry.path = trim_end(value, '/');
181 } else if (!strcmp(name, "name")) { 183 } else if (!strcmp(name, "name")) {
182 ctx.qry.name = xstrdup(value); 184 ctx.qry.name = xstrdup(value);
183 } else if (!strcmp(name, "mimetype")) { 185 } else if (!strcmp(name, "mimetype")) {
184 ctx.qry.mimetype = xstrdup(value); 186 ctx.qry.mimetype = xstrdup(value);
185 } else if (!strcmp(name, "s")){ 187 } else if (!strcmp(name, "s")){
186 ctx.qry.sort = xstrdup(value); 188 ctx.qry.sort = xstrdup(value);
187 } else if (!strcmp(name, "showmsg")) { 189 } else if (!strcmp(name, "showmsg")) {
188 ctx.qry.showmsg = atoi(value); 190 ctx.qry.showmsg = atoi(value);
189 } else if (!strcmp(name, "period")) { 191 } else if (!strcmp(name, "period")) {
190 ctx.qry.period = xstrdup(value); 192 ctx.qry.period = xstrdup(value);
191 } 193 }
192} 194}
193 195
194static void prepare_context(struct cgit_context *ctx) 196static void prepare_context(struct cgit_context *ctx)
195{ 197{
196 memset(ctx, 0, sizeof(ctx)); 198 memset(ctx, 0, sizeof(ctx));
197 ctx->cfg.agefile = "info/web/last-modified"; 199 ctx->cfg.agefile = "info/web/last-modified";
198 ctx->cfg.nocache = 0; 200 ctx->cfg.nocache = 0;
199 ctx->cfg.cache_size = 0; 201 ctx->cfg.cache_size = 0;
200 ctx->cfg.cache_dynamic_ttl = 5; 202 ctx->cfg.cache_dynamic_ttl = 5;
201 ctx->cfg.cache_max_create_time = 5; 203 ctx->cfg.cache_max_create_time = 5;
202 ctx->cfg.cache_repo_ttl = 5; 204 ctx->cfg.cache_repo_ttl = 5;
203 ctx->cfg.cache_root = CGIT_CACHE_ROOT; 205 ctx->cfg.cache_root = CGIT_CACHE_ROOT;
204 ctx->cfg.cache_root_ttl = 5; 206 ctx->cfg.cache_root_ttl = 5;
205 ctx->cfg.cache_static_ttl = -1; 207 ctx->cfg.cache_static_ttl = -1;
206 ctx->cfg.css = "/cgit.css"; 208 ctx->cfg.css = "/cgit.css";
207 ctx->cfg.logo = "/git-logo.png"; 209 ctx->cfg.logo = "/git-logo.png";
208 ctx->cfg.local_time = 0; 210 ctx->cfg.local_time = 0;
209 ctx->cfg.max_repo_count = 50; 211 ctx->cfg.max_repo_count = 50;
210 ctx->cfg.max_commit_count = 50; 212 ctx->cfg.max_commit_count = 50;
211 ctx->cfg.max_lock_attempts = 5; 213 ctx->cfg.max_lock_attempts = 5;
212 ctx->cfg.max_msg_len = 80; 214 ctx->cfg.max_msg_len = 80;
213 ctx->cfg.max_repodesc_len = 80; 215 ctx->cfg.max_repodesc_len = 80;
214 ctx->cfg.max_stats = 0; 216 ctx->cfg.max_stats = 0;
215 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 217 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
216 ctx->cfg.renamelimit = -1; 218 ctx->cfg.renamelimit = -1;
217 ctx->cfg.robots = "index, nofollow"; 219 ctx->cfg.robots = "index, nofollow";
218 ctx->cfg.root_title = "Git repository browser"; 220 ctx->cfg.root_title = "Git repository browser";
219 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 221 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
220 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 222 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
221 ctx->cfg.summary_branches = 10; 223 ctx->cfg.summary_branches = 10;
222 ctx->cfg.summary_log = 10; 224 ctx->cfg.summary_log = 10;
223 ctx->cfg.summary_tags = 10; 225 ctx->cfg.summary_tags = 10;
224 ctx->page.mimetype = "text/html"; 226 ctx->page.mimetype = "text/html";
225 ctx->page.charset = PAGE_ENCODING; 227 ctx->page.charset = PAGE_ENCODING;
226 ctx->page.filename = NULL; 228 ctx->page.filename = NULL;
227 ctx->page.size = 0; 229 ctx->page.size = 0;
228 ctx->page.modified = time(NULL); 230 ctx->page.modified = time(NULL);
229 ctx->page.expires = ctx->page.modified; 231 ctx->page.expires = ctx->page.modified;
230 ctx->page.etag = NULL; 232 ctx->page.etag = NULL;
231} 233}
232 234
233struct refmatch { 235struct refmatch {
234 char *req_ref; 236 char *req_ref;
235 char *first_ref; 237 char *first_ref;
236 int match; 238 int match;
237}; 239};
238 240
239int find_current_ref(const char *refname, const unsigned char *sha1, 241int find_current_ref(const char *refname, const unsigned char *sha1,
240 int flags, void *cb_data) 242 int flags, void *cb_data)
241{ 243{
242 struct refmatch *info; 244 struct refmatch *info;
243 245
244 info = (struct refmatch *)cb_data; 246 info = (struct refmatch *)cb_data;
245 if (!strcmp(refname, info->req_ref)) 247 if (!strcmp(refname, info->req_ref))
246 info->match = 1; 248 info->match = 1;
247 if (!info->first_ref) 249 if (!info->first_ref)
248 info->first_ref = xstrdup(refname); 250 info->first_ref = xstrdup(refname);
249 return info->match; 251 return info->match;
250} 252}
251 253
252char *find_default_branch(struct cgit_repo *repo) 254char *find_default_branch(struct cgit_repo *repo)
253{ 255{
254 struct refmatch info; 256 struct refmatch info;
255 char *ref; 257 char *ref;
256 258
257 info.req_ref = repo->defbranch; 259 info.req_ref = repo->defbranch;
258 info.first_ref = NULL; 260 info.first_ref = NULL;
259 info.match = 0; 261 info.match = 0;
260 for_each_branch_ref(find_current_ref, &info); 262 for_each_branch_ref(find_current_ref, &info);
261 if (info.match) 263 if (info.match)
262 ref = info.req_ref; 264 ref = info.req_ref;
263 else 265 else
264 ref = info.first_ref; 266 ref = info.first_ref;
265 if (ref) 267 if (ref)
266 ref = xstrdup(ref); 268 ref = xstrdup(ref);
267 return ref; 269 return ref;
268} 270}
269 271
270static int prepare_repo_cmd(struct cgit_context *ctx) 272static int prepare_repo_cmd(struct cgit_context *ctx)
271{ 273{
272 char *tmp; 274 char *tmp;
273 unsigned char sha1[20]; 275 unsigned char sha1[20];
274 int nongit = 0; 276 int nongit = 0;
275 277
276 setenv("GIT_DIR", ctx->repo->path, 1); 278 setenv("GIT_DIR", ctx->repo->path, 1);
277 setup_git_directory_gently(&nongit); 279 setup_git_directory_gently(&nongit);
278 if (nongit) { 280 if (nongit) {
279 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, 281 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
280 "config error"); 282 "config error");
281 tmp = fmt("Not a git repository: '%s'", ctx->repo->path); 283 tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
282 ctx->repo = NULL; 284 ctx->repo = NULL;
283 cgit_print_http_headers(ctx); 285 cgit_print_http_headers(ctx);
284 cgit_print_docstart(ctx); 286 cgit_print_docstart(ctx);
285 cgit_print_pageheader(ctx); 287 cgit_print_pageheader(ctx);
286 cgit_print_error(tmp); 288 cgit_print_error(tmp);
287 cgit_print_docend(); 289 cgit_print_docend();
288 return 1; 290 return 1;
289 } 291 }
290 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); 292 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc);
291 293
292 if (!ctx->qry.head) { 294 if (!ctx->qry.head) {
293 ctx->qry.nohead = 1; 295 ctx->qry.nohead = 1;
294 ctx->qry.head = find_default_branch(ctx->repo); 296 ctx->qry.head = find_default_branch(ctx->repo);
295 ctx->repo->defbranch = ctx->qry.head; 297 ctx->repo->defbranch = ctx->qry.head;
296 } 298 }
297 299
298 if (!ctx->qry.head) { 300 if (!ctx->qry.head) {
299 cgit_print_http_headers(ctx); 301 cgit_print_http_headers(ctx);
300 cgit_print_docstart(ctx); 302 cgit_print_docstart(ctx);
301 cgit_print_pageheader(ctx); 303 cgit_print_pageheader(ctx);
302 cgit_print_error("Repository seems to be empty"); 304 cgit_print_error("Repository seems to be empty");
303 cgit_print_docend(); 305 cgit_print_docend();
304 return 1; 306 return 1;
305 } 307 }
306 308
307 if (get_sha1(ctx->qry.head, sha1)) { 309 if (get_sha1(ctx->qry.head, sha1)) {
308 tmp = xstrdup(ctx->qry.head); 310 tmp = xstrdup(ctx->qry.head);
309 ctx->qry.head = ctx->repo->defbranch; 311 ctx->qry.head = ctx->repo->defbranch;
310 ctx->page.status = 404; 312 ctx->page.status = 404;
311 ctx->page.statusmsg = "not found"; 313 ctx->page.statusmsg = "not found";
312 cgit_print_http_headers(ctx); 314 cgit_print_http_headers(ctx);
313 cgit_print_docstart(ctx); 315 cgit_print_docstart(ctx);
314 cgit_print_pageheader(ctx); 316 cgit_print_pageheader(ctx);
315 cgit_print_error(fmt("Invalid branch: %s", tmp)); 317 cgit_print_error(fmt("Invalid branch: %s", tmp));
316 cgit_print_docend(); 318 cgit_print_docend();
317 return 1; 319 return 1;
318 } 320 }
319 return 0; 321 return 0;
320} 322}
321 323
322static void process_request(void *cbdata) 324static void process_request(void *cbdata)
323{ 325{
324 struct cgit_context *ctx = cbdata; 326 struct cgit_context *ctx = cbdata;
325 struct cgit_cmd *cmd; 327 struct cgit_cmd *cmd;
326 328
327 cmd = cgit_get_cmd(ctx); 329 cmd = cgit_get_cmd(ctx);
328 if (!cmd) { 330 if (!cmd) {
329 ctx->page.title = "cgit error"; 331 ctx->page.title = "cgit error";
330 cgit_print_http_headers(ctx); 332 cgit_print_http_headers(ctx);
331 cgit_print_docstart(ctx); 333 cgit_print_docstart(ctx);
332 cgit_print_pageheader(ctx); 334 cgit_print_pageheader(ctx);
333 cgit_print_error("Invalid request"); 335 cgit_print_error("Invalid request");
334 cgit_print_docend(); 336 cgit_print_docend();
335 return; 337 return;
336 } 338 }
337 339
338 if (cmd->want_repo && !ctx->repo) { 340 if (cmd->want_repo && !ctx->repo) {
339 cgit_print_http_headers(ctx); 341 cgit_print_http_headers(ctx);
340 cgit_print_docstart(ctx); 342 cgit_print_docstart(ctx);
341 cgit_print_pageheader(ctx); 343 cgit_print_pageheader(ctx);
342 cgit_print_error(fmt("No repository selected")); 344 cgit_print_error(fmt("No repository selected"));
343 cgit_print_docend(); 345 cgit_print_docend();
344 return; 346 return;
345 } 347 }
346 348
347 if (ctx->repo && prepare_repo_cmd(ctx)) 349 if (ctx->repo && prepare_repo_cmd(ctx))
348 return; 350 return;
349 351
350 if (cmd->want_layout) { 352 if (cmd->want_layout) {
351 cgit_print_http_headers(ctx); 353 cgit_print_http_headers(ctx);
352 cgit_print_docstart(ctx); 354 cgit_print_docstart(ctx);
353 cgit_print_pageheader(ctx); 355 cgit_print_pageheader(ctx);
354 } 356 }
355 357
356 cmd->fn(ctx); 358 cmd->fn(ctx);
357 359
358 if (cmd->want_layout) 360 if (cmd->want_layout)
359 cgit_print_docend(); 361 cgit_print_docend();
360} 362}
361 363
362int cmp_repos(const void *a, const void *b) 364int cmp_repos(const void *a, const void *b)
363{ 365{
364 const struct cgit_repo *ra = a, *rb = b; 366 const struct cgit_repo *ra = a, *rb = b;
365 return strcmp(ra->url, rb->url); 367 return strcmp(ra->url, rb->url);
366} 368}
367 369
368void print_repo(struct cgit_repo *repo) 370void print_repo(struct cgit_repo *repo)
369{ 371{
370 printf("repo.url=%s\n", repo->url); 372 printf("repo.url=%s\n", repo->url);
371 printf("repo.name=%s\n", repo->name); 373 printf("repo.name=%s\n", repo->name);
372 printf("repo.path=%s\n", repo->path); 374 printf("repo.path=%s\n", repo->path);
373 if (repo->owner) 375 if (repo->owner)
374 printf("repo.owner=%s\n", repo->owner); 376 printf("repo.owner=%s\n", repo->owner);
375 if (repo->desc) 377 if (repo->desc)
376 printf("repo.desc=%s\n", repo->desc); 378 printf("repo.desc=%s\n", repo->desc);
377 if (repo->readme) 379 if (repo->readme)
378 printf("repo.readme=%s\n", repo->readme); 380 printf("repo.readme=%s\n", repo->readme);
379 printf("\n"); 381 printf("\n");
380} 382}
381 383
382void print_repolist(struct cgit_repolist *list) 384void print_repolist(struct cgit_repolist *list)
383{ 385{
384 int i; 386 int i;
385 387
386 for(i = 0; i < list->count; i++) 388 for(i = 0; i < list->count; i++)
387 print_repo(&list->repos[i]); 389 print_repo(&list->repos[i]);
388} 390}
389 391
390 392
391static void cgit_parse_args(int argc, const char **argv) 393static void cgit_parse_args(int argc, const char **argv)
392{ 394{
393 int i; 395 int i;
394 int scan = 0; 396 int scan = 0;
395 397
396 for (i = 1; i < argc; i++) { 398 for (i = 1; i < argc; i++) {
397 if (!strncmp(argv[i], "--cache=", 8)) { 399 if (!strncmp(argv[i], "--cache=", 8)) {
398 ctx.cfg.cache_root = xstrdup(argv[i]+8); 400 ctx.cfg.cache_root = xstrdup(argv[i]+8);
399 } 401 }
400 if (!strcmp(argv[i], "--nocache")) { 402 if (!strcmp(argv[i], "--nocache")) {
401 ctx.cfg.nocache = 1; 403 ctx.cfg.nocache = 1;
402 } 404 }
403 if (!strncmp(argv[i], "--query=", 8)) { 405 if (!strncmp(argv[i], "--query=", 8)) {
404 ctx.qry.raw = xstrdup(argv[i]+8); 406 ctx.qry.raw = xstrdup(argv[i]+8);
405 } 407 }
406 if (!strncmp(argv[i], "--repo=", 7)) { 408 if (!strncmp(argv[i], "--repo=", 7)) {
407 ctx.qry.repo = xstrdup(argv[i]+7); 409 ctx.qry.repo = xstrdup(argv[i]+7);
408 } 410 }
409 if (!strncmp(argv[i], "--page=", 7)) { 411 if (!strncmp(argv[i], "--page=", 7)) {
410 ctx.qry.page = xstrdup(argv[i]+7); 412 ctx.qry.page = xstrdup(argv[i]+7);
411 } 413 }
412 if (!strncmp(argv[i], "--head=", 7)) { 414 if (!strncmp(argv[i], "--head=", 7)) {
413 ctx.qry.head = xstrdup(argv[i]+7); 415 ctx.qry.head = xstrdup(argv[i]+7);
414 ctx.qry.has_symref = 1; 416 ctx.qry.has_symref = 1;
415 } 417 }
416 if (!strncmp(argv[i], "--sha1=", 7)) { 418 if (!strncmp(argv[i], "--sha1=", 7)) {
417 ctx.qry.sha1 = xstrdup(argv[i]+7); 419 ctx.qry.sha1 = xstrdup(argv[i]+7);
418 ctx.qry.has_sha1 = 1; 420 ctx.qry.has_sha1 = 1;
419 } 421 }
420 if (!strncmp(argv[i], "--ofs=", 6)) { 422 if (!strncmp(argv[i], "--ofs=", 6)) {
421 ctx.qry.ofs = atoi(argv[i]+6); 423 ctx.qry.ofs = atoi(argv[i]+6);
422 } 424 }
423 if (!strncmp(argv[i], "--scan-tree=", 12)) { 425 if (!strncmp(argv[i], "--scan-tree=", 12)) {
424 scan++; 426 scan++;
425 scan_tree(argv[i] + 12); 427 scan_tree(argv[i] + 12);
426 } 428 }
427 } 429 }
428 if (scan) { 430 if (scan) {
429 qsort(cgit_repolist.repos, cgit_repolist.count, 431 qsort(cgit_repolist.repos, cgit_repolist.count,
430 sizeof(struct cgit_repo), cmp_repos); 432 sizeof(struct cgit_repo), cmp_repos);
431 print_repolist(&cgit_repolist); 433 print_repolist(&cgit_repolist);
432 exit(0); 434 exit(0);
433 } 435 }
434} 436}
435 437
436static int calc_ttl() 438static int calc_ttl()
437{ 439{
438 if (!ctx.repo) 440 if (!ctx.repo)
439 return ctx.cfg.cache_root_ttl; 441 return ctx.cfg.cache_root_ttl;
440 442
441 if (!ctx.qry.page) 443 if (!ctx.qry.page)
442 return ctx.cfg.cache_repo_ttl; 444 return ctx.cfg.cache_repo_ttl;
443 445
444 if (ctx.qry.has_symref) 446 if (ctx.qry.has_symref)
445 return ctx.cfg.cache_dynamic_ttl; 447 return ctx.cfg.cache_dynamic_ttl;
446 448
447 if (ctx.qry.has_sha1) 449 if (ctx.qry.has_sha1)
448 return ctx.cfg.cache_static_ttl; 450 return ctx.cfg.cache_static_ttl;
449 451
450 return ctx.cfg.cache_repo_ttl; 452 return ctx.cfg.cache_repo_ttl;
451} 453}
452 454
453int main(int argc, const char **argv) 455int main(int argc, const char **argv)
454{ 456{
455 const char *cgit_config_env = getenv("CGIT_CONFIG"); 457 const char *cgit_config_env = getenv("CGIT_CONFIG");
456 const char *method = getenv("REQUEST_METHOD"); 458 const char *method = getenv("REQUEST_METHOD");
457 const char *path; 459 const char *path;
458 char *qry; 460 char *qry;
459 int err, ttl; 461 int err, ttl;
460 462
461 prepare_context(&ctx); 463 prepare_context(&ctx);
462 cgit_repolist.length = 0; 464 cgit_repolist.length = 0;
463 cgit_repolist.count = 0; 465 cgit_repolist.count = 0;
464 cgit_repolist.repos = NULL; 466 cgit_repolist.repos = NULL;
465 467
466 if (getenv("SCRIPT_NAME")) 468 if (getenv("SCRIPT_NAME"))
467 ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME")); 469 ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME"));
468 if (getenv("QUERY_STRING")) 470 if (getenv("QUERY_STRING"))
469 ctx.qry.raw = xstrdup(getenv("QUERY_STRING")); 471 ctx.qry.raw = xstrdup(getenv("QUERY_STRING"));
470 cgit_parse_args(argc, argv); 472 cgit_parse_args(argc, argv);
471 parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG, 473 parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG,
472 config_cb); 474 config_cb);
473 ctx.repo = NULL; 475 ctx.repo = NULL;
474 http_parse_querystring(ctx.qry.raw, querystring_cb); 476 http_parse_querystring(ctx.qry.raw, querystring_cb);
475 477
476 /* If virtual-root isn't specified in cgitrc, lets pretend 478 /* If virtual-root isn't specified in cgitrc, lets pretend
477 * that virtual-root equals SCRIPT_NAME. 479 * that virtual-root equals SCRIPT_NAME.
478 */ 480 */
479 if (!ctx.cfg.virtual_root) 481 if (!ctx.cfg.virtual_root)
480 ctx.cfg.virtual_root = ctx.cfg.script_name; 482 ctx.cfg.virtual_root = ctx.cfg.script_name;
481 483
482 /* If no url parameter is specified on the querystring, lets 484 /* If no url parameter is specified on the querystring, lets
483 * use PATH_INFO as url. This allows cgit to work with virtual 485 * use PATH_INFO as url. This allows cgit to work with virtual
484 * urls without the need for rewriterules in the webserver (as 486 * urls without the need for rewriterules in the webserver (as
485 * long as PATH_INFO is included in the cache lookup key). 487 * long as PATH_INFO is included in the cache lookup key).
486 */ 488 */
487 path = getenv("PATH_INFO"); 489 path = getenv("PATH_INFO");
488 if (!ctx.qry.url && path) { 490 if (!ctx.qry.url && path) {
489 if (path[0] == '/') 491 if (path[0] == '/')
490 path++; 492 path++;
491 ctx.qry.url = xstrdup(path); 493 ctx.qry.url = xstrdup(path);
492 if (ctx.qry.raw) { 494 if (ctx.qry.raw) {
493 qry = ctx.qry.raw; 495 qry = ctx.qry.raw;
494 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); 496 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry));
495 free(qry); 497 free(qry);
496 } else 498 } else
497 ctx.qry.raw = ctx.qry.url; 499 ctx.qry.raw = ctx.qry.url;
498 cgit_parse_url(ctx.qry.url); 500 cgit_parse_url(ctx.qry.url);
499 } 501 }
500 502
501 ttl = calc_ttl(); 503 ttl = calc_ttl();
502 ctx.page.expires += ttl*60; 504 ctx.page.expires += ttl*60;
503 if (method && !strcmp(method, "HEAD")) 505 if (method && !strcmp(method, "HEAD"))
504 ctx.cfg.nocache = 1; 506 ctx.cfg.nocache = 1;
505 if (ctx.cfg.nocache) 507 if (ctx.cfg.nocache)
506 ctx.cfg.cache_size = 0; 508 ctx.cfg.cache_size = 0;
507 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, 509 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
508 ctx.qry.raw, ttl, process_request, &ctx); 510 ctx.qry.raw, ttl, process_request, &ctx);
509 if (err) 511 if (err)
510 cgit_print_error(fmt("Error processing page: %s (%d)", 512 cgit_print_error(fmt("Error processing page: %s (%d)",
511 strerror(err), err)); 513 strerror(err), err));
512 return err; 514 return err;
513} 515}