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