summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--Makefile2
-rw-r--r--cgit.c124
-rw-r--r--cgit.h14
-rw-r--r--cmd.c101
-rw-r--r--cmd.h15
-rw-r--r--parsing.c2
-rw-r--r--shared.c13
7 files changed, 165 insertions, 106 deletions
diff --git a/Makefile b/Makefile
index 7102908..d9ff7d8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,83 +1,83 @@
1CGIT_VERSION = v0.7.2 1CGIT_VERSION = v0.7.2
2CGIT_SCRIPT_NAME = cgit.cgi 2CGIT_SCRIPT_NAME = cgit.cgi
3CGIT_SCRIPT_PATH = /var/www/htdocs/cgit 3CGIT_SCRIPT_PATH = /var/www/htdocs/cgit
4CGIT_CONFIG = /etc/cgitrc 4CGIT_CONFIG = /etc/cgitrc
5CACHE_ROOT = /var/cache/cgit 5CACHE_ROOT = /var/cache/cgit
6SHA1_HEADER = <openssl/sha.h> 6SHA1_HEADER = <openssl/sha.h>
7GIT_VER = 1.5.4.1 7GIT_VER = 1.5.4.1
8GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 8GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2
9 9
10# 10#
11# Let the user override the above settings. 11# Let the user override the above settings.
12# 12#
13-include cgit.conf 13-include cgit.conf
14 14
15 15
16EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto 16EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto
17OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \ 17OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \
18 ui-summary.o ui-log.o ui-tree.o ui-commit.o ui-diff.o \ 18 ui-summary.o ui-log.o ui-tree.o ui-commit.o ui-diff.o \
19 ui-snapshot.o ui-blob.o ui-tag.o ui-refs.o ui-patch.o 19 ui-snapshot.o ui-blob.o ui-tag.o ui-refs.o ui-patch.o cmd.o
20 20
21 21
22ifdef NEEDS_LIBICONV 22ifdef NEEDS_LIBICONV
23 EXTLIBS += -liconv 23 EXTLIBS += -liconv
24endif 24endif
25 25
26 26
27.PHONY: all git test install clean distclean emptycache force-version get-git 27.PHONY: all git test install clean distclean emptycache force-version get-git
28 28
29all: cgit git 29all: cgit git
30 30
31VERSION: force-version 31VERSION: force-version
32 @./gen-version.sh "$(CGIT_VERSION)" 32 @./gen-version.sh "$(CGIT_VERSION)"
33-include VERSION 33-include VERSION
34 34
35 35
36CFLAGS += -g -Wall -Igit 36CFLAGS += -g -Wall -Igit
37CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER)' 37CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER)'
38CFLAGS += -DCGIT_VERSION='"$(CGIT_VERSION)"' 38CFLAGS += -DCGIT_VERSION='"$(CGIT_VERSION)"'
39CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"' 39CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"'
40CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"' 40CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"'
41CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"' 41CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"'
42 42
43 43
44cgit: cgit.c $(OBJECTS) 44cgit: cgit.c $(OBJECTS)
45 $(CC) $(CFLAGS) cgit.c -o cgit $(OBJECTS) $(EXTLIBS) 45 $(CC) $(CFLAGS) cgit.c -o cgit $(OBJECTS) $(EXTLIBS)
46 46
47$(OBJECTS): cgit.h git/xdiff/lib.a git/libgit.a VERSION 47$(OBJECTS): cgit.h git/xdiff/lib.a git/libgit.a VERSION
48 48
49git/xdiff/lib.a: | git 49git/xdiff/lib.a: | git
50 50
51git/libgit.a: | git 51git/libgit.a: | git
52 52
53git: 53git:
54 cd git && $(MAKE) xdiff/lib.a 54 cd git && $(MAKE) xdiff/lib.a
55 cd git && $(MAKE) libgit.a 55 cd git && $(MAKE) libgit.a
56 56
57test: all 57test: all
58 $(MAKE) -C tests 58 $(MAKE) -C tests
59 59
60install: all 60install: all
61 mkdir -p $(DESTDIR)$(CGIT_SCRIPT_PATH) 61 mkdir -p $(DESTDIR)$(CGIT_SCRIPT_PATH)
62 install cgit $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) 62 install cgit $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
63 install cgit.css $(DESTDIR)$(CGIT_SCRIPT_PATH)/cgit.css 63 install cgit.css $(DESTDIR)$(CGIT_SCRIPT_PATH)/cgit.css
64 install cgit.png $(DESTDIR)$(CGIT_SCRIPT_PATH)/cgit.png 64 install cgit.png $(DESTDIR)$(CGIT_SCRIPT_PATH)/cgit.png
65 65
66uninstall: 66uninstall:
67 rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) 67 rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
68 rm -f $(CGIT_SCRIPT_PATH)/cgit.css 68 rm -f $(CGIT_SCRIPT_PATH)/cgit.css
69 rm -f $(CGIT_SCRIPT_PATH)/cgit.png 69 rm -f $(CGIT_SCRIPT_PATH)/cgit.png
70 70
71clean: 71clean:
72 rm -f cgit VERSION *.o 72 rm -f cgit VERSION *.o
73 cd git && $(MAKE) clean 73 cd git && $(MAKE) clean
74 74
75distclean: clean 75distclean: clean
76 git clean -d -x 76 git clean -d -x
77 cd git && git clean -d -x 77 cd git && git clean -d -x
78 78
79emptycache: 79emptycache:
80 rm -rf $(DESTDIR)$(CACHE_ROOT)/* 80 rm -rf $(DESTDIR)$(CACHE_ROOT)/*
81 81
82get-git: 82get-git:
83 curl $(GIT_URL) | tar -xj && rm -rf git && mv git-$(GIT_VER) git 83 curl $(GIT_URL) | tar -xj && rm -rf git && mv git-$(GIT_VER) git
diff --git a/cgit.c b/cgit.c
index a83f0be..79e0e43 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,311 +1,281 @@
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 "cmd.h" 10#include "cmd.h"
11 11
12static int cgit_prepare_cache(struct cacheitem *item) 12static int cgit_prepare_cache(struct cacheitem *item)
13{ 13{
14 if (!ctx.repo && ctx.qry.repo) { 14 if (!ctx.repo && ctx.qry.repo) {
15 ctx.page.title = fmt("%s - %s", ctx.cfg.root_title, 15 ctx.page.title = fmt("%s - %s", ctx.cfg.root_title,
16 "Bad request"); 16 "Bad request");
17 cgit_print_http_headers(&ctx); 17 cgit_print_http_headers(&ctx);
18 cgit_print_docstart(&ctx); 18 cgit_print_docstart(&ctx);
19 cgit_print_pageheader(&ctx); 19 cgit_print_pageheader(&ctx);
20 cgit_print_error(fmt("Unknown repo: %s", ctx.qry.repo)); 20 cgit_print_error(fmt("Unknown repo: %s", ctx.qry.repo));
21 cgit_print_docend(); 21 cgit_print_docend();
22 return 0; 22 return 0;
23 } 23 }
24 24
25 if (!ctx.repo) { 25 if (!ctx.repo) {
26 item->name = xstrdup(fmt("%s/index.html", ctx.cfg.cache_root)); 26 item->name = xstrdup(fmt("%s/index.html", ctx.cfg.cache_root));
27 item->ttl = ctx.cfg.cache_root_ttl; 27 item->ttl = ctx.cfg.cache_root_ttl;
28 return 1; 28 return 1;
29 } 29 }
30 30
31 if (!cgit_cmd) { 31 if (!cgit_cmd) {
32 item->name = xstrdup(fmt("%s/%s/index.%s.html", ctx.cfg.cache_root, 32 item->name = xstrdup(fmt("%s/%s/index.%s.html", ctx.cfg.cache_root,
33 cache_safe_filename(ctx.repo->url), 33 cache_safe_filename(ctx.repo->url),
34 cache_safe_filename(ctx.qry.raw))); 34 cache_safe_filename(ctx.qry.raw)));
35 item->ttl = ctx.cfg.cache_repo_ttl; 35 item->ttl = ctx.cfg.cache_repo_ttl;
36 } else { 36 } else {
37 item->name = xstrdup(fmt("%s/%s/%s/%s.html", ctx.cfg.cache_root, 37 item->name = xstrdup(fmt("%s/%s/%s/%s.html", ctx.cfg.cache_root,
38 cache_safe_filename(ctx.repo->url), 38 cache_safe_filename(ctx.repo->url),
39 ctx.qry.page, 39 ctx.qry.page,
40 cache_safe_filename(ctx.qry.raw))); 40 cache_safe_filename(ctx.qry.raw)));
41 if (ctx.qry.has_symref) 41 if (ctx.qry.has_symref)
42 item->ttl = ctx.cfg.cache_dynamic_ttl; 42 item->ttl = ctx.cfg.cache_dynamic_ttl;
43 else if (ctx.qry.has_sha1) 43 else if (ctx.qry.has_sha1)
44 item->ttl = ctx.cfg.cache_static_ttl; 44 item->ttl = ctx.cfg.cache_static_ttl;
45 else 45 else
46 item->ttl = ctx.cfg.cache_repo_ttl; 46 item->ttl = ctx.cfg.cache_repo_ttl;
47 } 47 }
48 return 1; 48 return 1;
49} 49}
50 50
51struct refmatch { 51struct refmatch {
52 char *req_ref; 52 char *req_ref;
53 char *first_ref; 53 char *first_ref;
54 int match; 54 int match;
55}; 55};
56 56
57int find_current_ref(const char *refname, const unsigned char *sha1, 57int find_current_ref(const char *refname, const unsigned char *sha1,
58 int flags, void *cb_data) 58 int flags, void *cb_data)
59{ 59{
60 struct refmatch *info; 60 struct refmatch *info;
61 61
62 info = (struct refmatch *)cb_data; 62 info = (struct refmatch *)cb_data;
63 if (!strcmp(refname, info->req_ref)) 63 if (!strcmp(refname, info->req_ref))
64 info->match = 1; 64 info->match = 1;
65 if (!info->first_ref) 65 if (!info->first_ref)
66 info->first_ref = xstrdup(refname); 66 info->first_ref = xstrdup(refname);
67 return info->match; 67 return info->match;
68} 68}
69 69
70char *find_default_branch(struct cgit_repo *repo) 70char *find_default_branch(struct cgit_repo *repo)
71{ 71{
72 struct refmatch info; 72 struct refmatch info;
73 73
74 info.req_ref = repo->defbranch; 74 info.req_ref = repo->defbranch;
75 info.first_ref = NULL; 75 info.first_ref = NULL;
76 info.match = 0; 76 info.match = 0;
77 for_each_branch_ref(find_current_ref, &info); 77 for_each_branch_ref(find_current_ref, &info);
78 if (info.match) 78 if (info.match)
79 return info.req_ref; 79 return info.req_ref;
80 else 80 else
81 return info.first_ref; 81 return info.first_ref;
82} 82}
83 83
84static void cgit_print_repo_page() 84static int prepare_repo_cmd(struct cgit_context *ctx)
85{ 85{
86 char *tmp; 86 char *tmp;
87 int show_search;
88 unsigned char sha1[20]; 87 unsigned char sha1[20];
89 int nongit = 0; 88 int nongit = 0;
90 89
91 setenv("GIT_DIR", ctx.repo->path, 1); 90 setenv("GIT_DIR", ctx->repo->path, 1);
92 setup_git_directory_gently(&nongit); 91 setup_git_directory_gently(&nongit);
93 if (nongit) { 92 if (nongit) {
94 ctx.page.title = fmt("%s - %s", ctx.cfg.root_title, 93 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
95 "config error"); 94 "config error");
96 tmp = fmt("Not a git repository: '%s'", ctx.repo->path); 95 tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
97 ctx.repo = NULL; 96 ctx->repo = NULL;
98 cgit_print_http_headers(&ctx); 97 cgit_print_http_headers(ctx);
99 cgit_print_docstart(&ctx); 98 cgit_print_docstart(ctx);
100 cgit_print_pageheader(&ctx); 99 cgit_print_pageheader(ctx);
101 cgit_print_error(tmp); 100 cgit_print_error(tmp);
102 cgit_print_docend(); 101 cgit_print_docend();
103 return; 102 return 1;
104 } 103 }
104 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc);
105 105
106 ctx.page.title = fmt("%s - %s", ctx.repo->name, ctx.repo->desc); 106 if (!ctx->qry.head) {
107 show_search = 0; 107 ctx->qry.head = xstrdup(find_default_branch(ctx->repo));
108 108 ctx->repo->defbranch = ctx->qry.head;
109 if (!ctx.qry.head) {
110 ctx.qry.head = xstrdup(find_default_branch(ctx.repo));
111 ctx.repo->defbranch = ctx.qry.head;
112 } 109 }
113 110
114 if (!ctx.qry.head) { 111 if (!ctx->qry.head) {
115 cgit_print_http_headers(&ctx); 112 cgit_print_http_headers(ctx);
116 cgit_print_docstart(&ctx); 113 cgit_print_docstart(ctx);
117 cgit_print_pageheader(&ctx); 114 cgit_print_pageheader(ctx);
118 cgit_print_error("Repository seems to be empty"); 115 cgit_print_error("Repository seems to be empty");
119 cgit_print_docend(); 116 cgit_print_docend();
120 return; 117 return 1;
121 } 118 }
122 119
123 if (get_sha1(ctx.qry.head, sha1)) { 120 if (get_sha1(ctx->qry.head, sha1)) {
124 tmp = xstrdup(ctx.qry.head); 121 tmp = xstrdup(ctx->qry.head);
125 ctx.qry.head = ctx.repo->defbranch; 122 ctx->qry.head = ctx->repo->defbranch;
126 cgit_print_http_headers(&ctx); 123 cgit_print_http_headers(ctx);
127 cgit_print_docstart(&ctx); 124 cgit_print_docstart(ctx);
128 cgit_print_pageheader(&ctx); 125 cgit_print_pageheader(ctx);
129 cgit_print_error(fmt("Invalid branch: %s", tmp)); 126 cgit_print_error(fmt("Invalid branch: %s", tmp));
130 cgit_print_docend(); 127 cgit_print_docend();
131 return; 128 return 1;
132 } 129 }
133 130 return 0;
134 if ((cgit_cmd == CMD_SNAPSHOT) && ctx.repo->snapshots) {
135 cgit_print_snapshot(ctx.qry.head, ctx.qry.sha1,
136 cgit_repobasename(ctx.repo->url),
137 ctx.qry.path,
138 ctx.repo->snapshots );
139 return;
140 } 131 }
141 132
142 if (cgit_cmd == CMD_PATCH) { 133static void process_request(struct cgit_context *ctx)
143 cgit_print_patch(ctx.qry.sha1); 134{
135 struct cgit_cmd *cmd;
136
137 cmd = cgit_get_cmd(ctx);
138 if (!cmd) {
139 ctx->page.title = "cgit error";
140 ctx->repo = NULL;
141 cgit_print_http_headers(ctx);
142 cgit_print_docstart(ctx);
143 cgit_print_pageheader(ctx);
144 cgit_print_error("Invalid request");
145 cgit_print_docend();
144 return; 146 return;
145 } 147 }
146 148
147 if (cgit_cmd == CMD_BLOB) { 149 if (cmd->want_repo && prepare_repo_cmd(ctx))
148 cgit_print_blob(ctx.qry.sha1, ctx.qry.path);
149 return; 150 return;
150 }
151 151
152 show_search = (cgit_cmd == CMD_LOG); 152 if (cmd->want_layout) {
153 cgit_print_http_headers(&ctx); 153 cgit_print_http_headers(ctx);
154 cgit_print_docstart(&ctx); 154 cgit_print_docstart(ctx);
155 if (!cgit_cmd) { 155 cgit_print_pageheader(ctx);
156 cgit_print_pageheader(&ctx);
157 cgit_print_summary();
158 cgit_print_docend();
159 return;
160 } 156 }
161 157
162 cgit_print_pageheader(&ctx); 158 cmd->fn(ctx);
163 159
164 switch(cgit_cmd) { 160 if (cmd->want_layout)
165 case CMD_LOG:
166 cgit_print_log(ctx.qry.sha1, ctx.qry.ofs,
167 ctx.cfg.max_commit_count, ctx.qry.grep, ctx.qry.search,
168 ctx.qry.path, 1);
169 break;
170 case CMD_TREE:
171 cgit_print_tree(ctx.qry.sha1, ctx.qry.path);
172 break;
173 case CMD_COMMIT:
174 cgit_print_commit(ctx.qry.sha1);
175 break;
176 case CMD_REFS:
177 cgit_print_refs();
178 break;
179 case CMD_TAG:
180 cgit_print_tag(ctx.qry.sha1);
181 break;
182 case CMD_DIFF:
183 cgit_print_diff(ctx.qry.sha1, ctx.qry.sha2, ctx.qry.path);
184 break;
185 default:
186 cgit_print_error("Invalid request");
187 }
188 cgit_print_docend(); 161 cgit_print_docend();
189} 162}
190 163
191static long ttl_seconds(long ttl) 164static long ttl_seconds(long ttl)
192{ 165{
193 if (ttl<0) 166 if (ttl<0)
194 return 60 * 60 * 24 * 365; 167 return 60 * 60 * 24 * 365;
195 else 168 else
196 return ttl * 60; 169 return ttl * 60;
197} 170}
198 171
199static void cgit_fill_cache(struct cacheitem *item, int use_cache) 172static void cgit_fill_cache(struct cacheitem *item, int use_cache)
200{ 173{
201 int stdout2; 174 int stdout2;
202 175
203 if (use_cache) { 176 if (use_cache) {
204 stdout2 = chk_positive(dup(STDOUT_FILENO), 177 stdout2 = chk_positive(dup(STDOUT_FILENO),
205 "Preserving STDOUT"); 178 "Preserving STDOUT");
206 chk_zero(close(STDOUT_FILENO), "Closing STDOUT"); 179 chk_zero(close(STDOUT_FILENO), "Closing STDOUT");
207 chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)"); 180 chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)");
208 } 181 }
209 182
210 ctx.page.modified = time(NULL); 183 ctx.page.modified = time(NULL);
211 ctx.page.expires = ctx.page.modified + ttl_seconds(item->ttl); 184 ctx.page.expires = ctx.page.modified + ttl_seconds(item->ttl);
212 if (ctx.repo) 185 process_request(&ctx);
213 cgit_print_repo_page();
214 else
215 cgit_print_repolist();
216 186
217 if (use_cache) { 187 if (use_cache) {
218 chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT"); 188 chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT");
219 chk_positive(dup2(stdout2, STDOUT_FILENO), 189 chk_positive(dup2(stdout2, STDOUT_FILENO),
220 "Restoring original STDOUT"); 190 "Restoring original STDOUT");
221 chk_zero(close(stdout2), "Closing temporary STDOUT"); 191 chk_zero(close(stdout2), "Closing temporary STDOUT");
222 } 192 }
223} 193}
224 194
225static void cgit_check_cache(struct cacheitem *item) 195static void cgit_check_cache(struct cacheitem *item)
226{ 196{
227 int i = 0; 197 int i = 0;
228 198
229 top: 199 top:
230 if (++i > ctx.cfg.max_lock_attempts) { 200 if (++i > ctx.cfg.max_lock_attempts) {
231 die("cgit_refresh_cache: unable to lock %s: %s", 201 die("cgit_refresh_cache: unable to lock %s: %s",
232 item->name, strerror(errno)); 202 item->name, strerror(errno));
233 } 203 }
234 if (!cache_exist(item)) { 204 if (!cache_exist(item)) {
235 if (!cache_lock(item)) { 205 if (!cache_lock(item)) {
236 sleep(1); 206 sleep(1);
237 goto top; 207 goto top;
238 } 208 }
239 if (!cache_exist(item)) { 209 if (!cache_exist(item)) {
240 cgit_fill_cache(item, 1); 210 cgit_fill_cache(item, 1);
241 cache_unlock(item); 211 cache_unlock(item);
242 } else { 212 } else {
243 cache_cancel_lock(item); 213 cache_cancel_lock(item);
244 } 214 }
245 } else if (cache_expired(item) && cache_lock(item)) { 215 } else if (cache_expired(item) && cache_lock(item)) {
246 if (cache_expired(item)) { 216 if (cache_expired(item)) {
247 cgit_fill_cache(item, 1); 217 cgit_fill_cache(item, 1);
248 cache_unlock(item); 218 cache_unlock(item);
249 } else { 219 } else {
250 cache_cancel_lock(item); 220 cache_cancel_lock(item);
251 } 221 }
252 } 222 }
253} 223}
254 224
255static void cgit_print_cache(struct cacheitem *item) 225static void cgit_print_cache(struct cacheitem *item)
256{ 226{
257 static char buf[4096]; 227 static char buf[4096];
258 ssize_t i; 228 ssize_t i;
259 229
260 int fd = open(item->name, O_RDONLY); 230 int fd = open(item->name, O_RDONLY);
261 if (fd<0) 231 if (fd<0)
262 die("Unable to open cached file %s", item->name); 232 die("Unable to open cached file %s", item->name);
263 233
264 while((i=read(fd, buf, sizeof(buf))) > 0) 234 while((i=read(fd, buf, sizeof(buf))) > 0)
265 write(STDOUT_FILENO, buf, i); 235 write(STDOUT_FILENO, buf, i);
266 236
267 close(fd); 237 close(fd);
268} 238}
269 239
270static void cgit_parse_args(int argc, const char **argv) 240static void cgit_parse_args(int argc, const char **argv)
271{ 241{
272 int i; 242 int i;
273 243
274 for (i = 1; i < argc; i++) { 244 for (i = 1; i < argc; i++) {
275 if (!strncmp(argv[i], "--cache=", 8)) { 245 if (!strncmp(argv[i], "--cache=", 8)) {
276 ctx.cfg.cache_root = xstrdup(argv[i]+8); 246 ctx.cfg.cache_root = xstrdup(argv[i]+8);
277 } 247 }
278 if (!strcmp(argv[i], "--nocache")) { 248 if (!strcmp(argv[i], "--nocache")) {
279 ctx.cfg.nocache = 1; 249 ctx.cfg.nocache = 1;
280 } 250 }
281 if (!strncmp(argv[i], "--query=", 8)) { 251 if (!strncmp(argv[i], "--query=", 8)) {
282 ctx.qry.raw = xstrdup(argv[i]+8); 252 ctx.qry.raw = xstrdup(argv[i]+8);
283 } 253 }
284 if (!strncmp(argv[i], "--repo=", 7)) { 254 if (!strncmp(argv[i], "--repo=", 7)) {
285 ctx.qry.repo = xstrdup(argv[i]+7); 255 ctx.qry.repo = xstrdup(argv[i]+7);
286 } 256 }
287 if (!strncmp(argv[i], "--page=", 7)) { 257 if (!strncmp(argv[i], "--page=", 7)) {
288 ctx.qry.page = xstrdup(argv[i]+7); 258 ctx.qry.page = xstrdup(argv[i]+7);
289 } 259 }
290 if (!strncmp(argv[i], "--head=", 7)) { 260 if (!strncmp(argv[i], "--head=", 7)) {
291 ctx.qry.head = xstrdup(argv[i]+7); 261 ctx.qry.head = xstrdup(argv[i]+7);
292 ctx.qry.has_symref = 1; 262 ctx.qry.has_symref = 1;
293 } 263 }
294 if (!strncmp(argv[i], "--sha1=", 7)) { 264 if (!strncmp(argv[i], "--sha1=", 7)) {
295 ctx.qry.sha1 = xstrdup(argv[i]+7); 265 ctx.qry.sha1 = xstrdup(argv[i]+7);
296 ctx.qry.has_sha1 = 1; 266 ctx.qry.has_sha1 = 1;
297 } 267 }
298 if (!strncmp(argv[i], "--ofs=", 6)) { 268 if (!strncmp(argv[i], "--ofs=", 6)) {
299 ctx.qry.ofs = atoi(argv[i]+6); 269 ctx.qry.ofs = atoi(argv[i]+6);
300 } 270 }
301 } 271 }
302} 272}
303 273
304int main(int argc, const char **argv) 274int main(int argc, const char **argv)
305{ 275{
306 struct cacheitem item; 276 struct cacheitem item;
307 const char *cgit_config_env = getenv("CGIT_CONFIG"); 277 const char *cgit_config_env = getenv("CGIT_CONFIG");
308 278
309 cgit_prepare_context(&ctx); 279 cgit_prepare_context(&ctx);
310 item.st.st_mtime = time(NULL); 280 item.st.st_mtime = time(NULL);
311 cgit_repolist.length = 0; 281 cgit_repolist.length = 0;
diff --git a/cgit.h b/cgit.h
index 40e2d40..295441b 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,296 +1,282 @@
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#include <utf8.h> 19#include <utf8.h>
20 20
21 21
22/* 22/*
23 * The valid cgit repo-commands
24 */
25#define CMD_LOG 1
26#define CMD_COMMIT 2
27#define CMD_DIFF 3
28#define CMD_TREE 4
29#define CMD_BLOB 5
30#define CMD_SNAPSHOT 6
31#define CMD_TAG 7
32#define CMD_REFS 8
33#define CMD_PATCH 9
34
35/*
36 * Dateformats used on misc. pages 23 * Dateformats used on misc. pages
37 */ 24 */
38#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S" 25#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S"
39#define FMT_SHORTDATE "%Y-%m-%d" 26#define FMT_SHORTDATE "%Y-%m-%d"
40 27
41 28
42/* 29/*
43 * Limits used for relative dates 30 * Limits used for relative dates
44 */ 31 */
45#define TM_MIN 60 32#define TM_MIN 60
46#define TM_HOUR (TM_MIN * 60) 33#define TM_HOUR (TM_MIN * 60)
47#define TM_DAY (TM_HOUR * 24) 34#define TM_DAY (TM_HOUR * 24)
48#define TM_WEEK (TM_DAY * 7) 35#define TM_WEEK (TM_DAY * 7)
49#define TM_YEAR (TM_DAY * 365) 36#define TM_YEAR (TM_DAY * 365)
50#define TM_MONTH (TM_YEAR / 12.0) 37#define TM_MONTH (TM_YEAR / 12.0)
51 38
52 39
53/* 40/*
54 * Default encoding 41 * Default encoding
55 */ 42 */
56#define PAGE_ENCODING "UTF-8" 43#define PAGE_ENCODING "UTF-8"
57 44
58typedef void (*configfn)(const char *name, const char *value); 45typedef void (*configfn)(const char *name, const char *value);
59typedef void (*filepair_fn)(struct diff_filepair *pair); 46typedef void (*filepair_fn)(struct diff_filepair *pair);
60typedef void (*linediff_fn)(char *line, int len); 47typedef void (*linediff_fn)(char *line, int len);
61 48
62struct cacheitem { 49struct cacheitem {
63 char *name; 50 char *name;
64 struct stat st; 51 struct stat st;
65 int ttl; 52 int ttl;
66 int fd; 53 int fd;
67}; 54};
68 55
69struct cgit_repo { 56struct cgit_repo {
70 char *url; 57 char *url;
71 char *name; 58 char *name;
72 char *path; 59 char *path;
73 char *desc; 60 char *desc;
74 char *owner; 61 char *owner;
75 char *defbranch; 62 char *defbranch;
76 char *group; 63 char *group;
77 char *module_link; 64 char *module_link;
78 char *readme; 65 char *readme;
79 char *clone_url; 66 char *clone_url;
80 int snapshots; 67 int snapshots;
81 int enable_log_filecount; 68 int enable_log_filecount;
82 int enable_log_linecount; 69 int enable_log_linecount;
83}; 70};
84 71
85struct cgit_repolist { 72struct cgit_repolist {
86 int length; 73 int length;
87 int count; 74 int count;
88 struct cgit_repo *repos; 75 struct cgit_repo *repos;
89}; 76};
90 77
91struct commitinfo { 78struct commitinfo {
92 struct commit *commit; 79 struct commit *commit;
93 char *author; 80 char *author;
94 char *author_email; 81 char *author_email;
95 unsigned long author_date; 82 unsigned long author_date;
96 char *committer; 83 char *committer;
97 char *committer_email; 84 char *committer_email;
98 unsigned long committer_date; 85 unsigned long committer_date;
99 char *subject; 86 char *subject;
100 char *msg; 87 char *msg;
101 char *msg_encoding; 88 char *msg_encoding;
102}; 89};
103 90
104struct taginfo { 91struct taginfo {
105 char *tagger; 92 char *tagger;
106 char *tagger_email; 93 char *tagger_email;
107 int tagger_date; 94 int tagger_date;
108 char *msg; 95 char *msg;
109}; 96};
110 97
111struct refinfo { 98struct refinfo {
112 const char *refname; 99 const char *refname;
113 struct object *object; 100 struct object *object;
114 union { 101 union {
115 struct taginfo *tag; 102 struct taginfo *tag;
116 struct commitinfo *commit; 103 struct commitinfo *commit;
117 }; 104 };
118}; 105};
119 106
120struct reflist { 107struct reflist {
121 struct refinfo **refs; 108 struct refinfo **refs;
122 int alloc; 109 int alloc;
123 int count; 110 int count;
124}; 111};
125 112
126struct cgit_query { 113struct cgit_query {
127 int has_symref; 114 int has_symref;
128 int has_sha1; 115 int has_sha1;
129 char *raw; 116 char *raw;
130 char *repo; 117 char *repo;
131 char *page; 118 char *page;
132 char *search; 119 char *search;
133 char *grep; 120 char *grep;
134 char *head; 121 char *head;
135 char *sha1; 122 char *sha1;
136 char *sha2; 123 char *sha2;
137 char *path; 124 char *path;
138 char *name; 125 char *name;
139 int ofs; 126 int ofs;
140}; 127};
141 128
142struct cgit_config { 129struct cgit_config {
143 char *agefile; 130 char *agefile;
144 char *cache_root; 131 char *cache_root;
145 char *clone_prefix; 132 char *clone_prefix;
146 char *css; 133 char *css;
147 char *index_header; 134 char *index_header;
148 char *index_info; 135 char *index_info;
149 char *logo; 136 char *logo;
150 char *logo_link; 137 char *logo_link;
151 char *module_link; 138 char *module_link;
152 char *repo_group; 139 char *repo_group;
153 char *robots; 140 char *robots;
154 char *root_title; 141 char *root_title;
155 char *script_name; 142 char *script_name;
156 char *virtual_root; 143 char *virtual_root;
157 int cache_dynamic_ttl; 144 int cache_dynamic_ttl;
158 int cache_max_create_time; 145 int cache_max_create_time;
159 int cache_repo_ttl; 146 int cache_repo_ttl;
160 int cache_root_ttl; 147 int cache_root_ttl;
161 int cache_static_ttl; 148 int cache_static_ttl;
162 int enable_index_links; 149 int enable_index_links;
163 int enable_log_filecount; 150 int enable_log_filecount;
164 int enable_log_linecount; 151 int enable_log_linecount;
165 int max_commit_count; 152 int max_commit_count;
166 int max_lock_attempts; 153 int max_lock_attempts;
167 int max_msg_len; 154 int max_msg_len;
168 int max_repodesc_len; 155 int max_repodesc_len;
169 int nocache; 156 int nocache;
170 int renamelimit; 157 int renamelimit;
171 int snapshots; 158 int snapshots;
172 int summary_branches; 159 int summary_branches;
173 int summary_log; 160 int summary_log;
174 int summary_tags; 161 int summary_tags;
175}; 162};
176 163
177struct cgit_page { 164struct cgit_page {
178 time_t modified; 165 time_t modified;
179 time_t expires; 166 time_t expires;
180 char *mimetype; 167 char *mimetype;
181 char *charset; 168 char *charset;
182 char *filename; 169 char *filename;
183 char *title; 170 char *title;
184}; 171};
185 172
186struct cgit_context { 173struct cgit_context {
187 struct cgit_query qry; 174 struct cgit_query qry;
188 struct cgit_config cfg; 175 struct cgit_config cfg;
189 struct cgit_repo *repo; 176 struct cgit_repo *repo;
190 struct cgit_page page; 177 struct cgit_page page;
191}; 178};
192 179
193extern const char *cgit_version; 180extern const char *cgit_version;
194 181
195extern struct cgit_repolist cgit_repolist; 182extern struct cgit_repolist cgit_repolist;
196extern struct cgit_context ctx; 183extern struct cgit_context ctx;
197extern int cgit_cmd; 184extern int cgit_cmd;
198 185
199extern void cgit_prepare_context(struct cgit_context *ctx); 186extern void cgit_prepare_context(struct cgit_context *ctx);
200extern int cgit_get_cmd_index(const char *cmd);
201extern struct cgit_repo *cgit_get_repoinfo(const char *url); 187extern struct cgit_repo *cgit_get_repoinfo(const char *url);
202extern void cgit_global_config_cb(const char *name, const char *value); 188extern void cgit_global_config_cb(const char *name, const char *value);
203extern void cgit_repo_config_cb(const char *name, const char *value); 189extern void cgit_repo_config_cb(const char *name, const char *value);
204extern void cgit_querystring_cb(const char *name, const char *value); 190extern void cgit_querystring_cb(const char *name, const char *value);
205 191
206extern int chk_zero(int result, char *msg); 192extern int chk_zero(int result, char *msg);
207extern int chk_positive(int result, char *msg); 193extern int chk_positive(int result, char *msg);
208extern int chk_non_negative(int result, char *msg); 194extern int chk_non_negative(int result, char *msg);
209 195
210extern int hextoint(char c); 196extern int hextoint(char c);
211extern char *trim_end(const char *str, char c); 197extern char *trim_end(const char *str, char c);
212extern char *strlpart(char *txt, int maxlen); 198extern char *strlpart(char *txt, int maxlen);
213extern char *strrpart(char *txt, int maxlen); 199extern char *strrpart(char *txt, int maxlen);
214 200
215extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); 201extern void cgit_add_ref(struct reflist *list, struct refinfo *ref);
216extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, 202extern int cgit_refs_cb(const char *refname, const unsigned char *sha1,
217 int flags, void *cb_data); 203 int flags, void *cb_data);
218 204
219extern void *cgit_free_commitinfo(struct commitinfo *info); 205extern void *cgit_free_commitinfo(struct commitinfo *info);
220 206
221extern int cgit_diff_files(const unsigned char *old_sha1, 207extern int cgit_diff_files(const unsigned char *old_sha1,
222 const unsigned char *new_sha1, 208 const unsigned char *new_sha1,
223 linediff_fn fn); 209 linediff_fn fn);
224 210
225extern void cgit_diff_tree(const unsigned char *old_sha1, 211extern void cgit_diff_tree(const unsigned char *old_sha1,
226 const unsigned char *new_sha1, 212 const unsigned char *new_sha1,
227 filepair_fn fn, const char *prefix); 213 filepair_fn fn, const char *prefix);
228 214
229extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 215extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
230 216
231extern char *fmt(const char *format,...); 217extern char *fmt(const char *format,...);
232 218
233extern int cgit_read_config(const char *filename, configfn fn); 219extern int cgit_read_config(const char *filename, configfn fn);
234extern int cgit_parse_query(char *txt, configfn fn); 220extern int cgit_parse_query(char *txt, configfn fn);
235extern struct commitinfo *cgit_parse_commit(struct commit *commit); 221extern struct commitinfo *cgit_parse_commit(struct commit *commit);
236extern struct taginfo *cgit_parse_tag(struct tag *tag); 222extern struct taginfo *cgit_parse_tag(struct tag *tag);
237extern void cgit_parse_url(const char *url); 223extern void cgit_parse_url(const char *url);
238 224
239extern char *cache_safe_filename(const char *unsafe); 225extern char *cache_safe_filename(const char *unsafe);
240extern int cache_lock(struct cacheitem *item); 226extern int cache_lock(struct cacheitem *item);
241extern int cache_unlock(struct cacheitem *item); 227extern int cache_unlock(struct cacheitem *item);
242extern int cache_cancel_lock(struct cacheitem *item); 228extern int cache_cancel_lock(struct cacheitem *item);
243extern int cache_exist(struct cacheitem *item); 229extern int cache_exist(struct cacheitem *item);
244extern int cache_expired(struct cacheitem *item); 230extern int cache_expired(struct cacheitem *item);
245 231
246extern char *cgit_repourl(const char *reponame); 232extern char *cgit_repourl(const char *reponame);
247extern char *cgit_fileurl(const char *reponame, const char *pagename, 233extern char *cgit_fileurl(const char *reponame, const char *pagename,
248 const char *filename, const char *query); 234 const char *filename, const char *query);
249extern char *cgit_pageurl(const char *reponame, const char *pagename, 235extern char *cgit_pageurl(const char *reponame, const char *pagename,
250 const char *query); 236 const char *query);
251 237
252extern const char *cgit_repobasename(const char *reponame); 238extern const char *cgit_repobasename(const char *reponame);
253 239
254extern void cgit_tree_link(char *name, char *title, char *class, char *head, 240extern void cgit_tree_link(char *name, char *title, char *class, char *head,
255 char *rev, char *path); 241 char *rev, char *path);
256extern void cgit_log_link(char *name, char *title, char *class, char *head, 242extern void cgit_log_link(char *name, char *title, char *class, char *head,
257 char *rev, char *path, int ofs, char *grep, 243 char *rev, char *path, int ofs, char *grep,
258 char *pattern); 244 char *pattern);
259extern void cgit_commit_link(char *name, char *title, char *class, char *head, 245extern void cgit_commit_link(char *name, char *title, char *class, char *head,
260 char *rev); 246 char *rev);
261extern void cgit_refs_link(char *name, char *title, char *class, char *head, 247extern void cgit_refs_link(char *name, char *title, char *class, char *head,
262 char *rev, char *path); 248 char *rev, char *path);
263extern void cgit_snapshot_link(char *name, char *title, char *class, 249extern void cgit_snapshot_link(char *name, char *title, char *class,
264 char *head, char *rev, char *archivename); 250 char *head, char *rev, char *archivename);
265extern void cgit_diff_link(char *name, char *title, char *class, char *head, 251extern void cgit_diff_link(char *name, char *title, char *class, char *head,
266 char *new_rev, char *old_rev, char *path); 252 char *new_rev, char *old_rev, char *path);
267 253
268extern void cgit_object_link(struct object *obj); 254extern void cgit_object_link(struct object *obj);
269 255
270extern void cgit_print_error(char *msg); 256extern void cgit_print_error(char *msg);
271extern void cgit_print_date(time_t secs, char *format); 257extern void cgit_print_date(time_t secs, char *format);
272extern void cgit_print_age(time_t t, time_t max_relative, char *format); 258extern void cgit_print_age(time_t t, time_t max_relative, char *format);
273extern void cgit_print_http_headers(struct cgit_context *ctx); 259extern void cgit_print_http_headers(struct cgit_context *ctx);
274extern void cgit_print_docstart(struct cgit_context *ctx); 260extern void cgit_print_docstart(struct cgit_context *ctx);
275extern void cgit_print_docend(); 261extern void cgit_print_docend();
276extern void cgit_print_pageheader(struct cgit_context *ctx); 262extern void cgit_print_pageheader(struct cgit_context *ctx);
277extern void cgit_print_filemode(unsigned short mode); 263extern void cgit_print_filemode(unsigned short mode);
278extern void cgit_print_branches(int maxcount); 264extern void cgit_print_branches(int maxcount);
279extern void cgit_print_tags(int maxcount); 265extern void cgit_print_tags(int maxcount);
280 266
281extern void cgit_print_repolist(); 267extern void cgit_print_repolist();
282extern void cgit_print_summary(); 268extern void cgit_print_summary();
283extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, 269extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep,
284 char *pattern, char *path, int pager); 270 char *pattern, char *path, int pager);
285extern void cgit_print_blob(const char *hex, char *path); 271extern void cgit_print_blob(const char *hex, char *path);
286extern void cgit_print_tree(const char *rev, char *path); 272extern void cgit_print_tree(const char *rev, char *path);
287extern void cgit_print_commit(char *hex); 273extern void cgit_print_commit(char *hex);
288extern void cgit_print_refs(); 274extern void cgit_print_refs();
289extern void cgit_print_tag(char *revname); 275extern void cgit_print_tag(char *revname);
290extern void cgit_print_diff(const char *new_hex, const char *old_hex, const char *prefix); 276extern void cgit_print_diff(const char *new_hex, const char *old_hex, const char *prefix);
291extern void cgit_print_patch(char *hex); 277extern void cgit_print_patch(char *hex);
292extern void cgit_print_snapshot(const char *head, const char *hex, 278extern void cgit_print_snapshot(const char *head, const char *hex,
293 const char *prefix, const char *filename, 279 const char *prefix, const char *filename,
294 int snapshot); 280 int snapshot);
295extern void cgit_print_snapshot_links(const char *repo, const char *head, 281extern void cgit_print_snapshot_links(const char *repo, const char *head,
296 const char *hex, int snapshots); 282 const char *hex, int snapshots);
diff --git a/cmd.c b/cmd.c
new file mode 100644
index 0000000..489a11c
--- a/dev/null
+++ b/cmd.c
@@ -0,0 +1,101 @@
1/* cmd.c: the cgit command dispatcher
2 *
3 * Copyright (C) 2008 Lars Hjemli
4 *
5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text)
7 */
8
9#include "cgit.h"
10#include "cmd.h"
11
12static void blob_fn(struct cgit_context *ctx)
13{
14 cgit_print_blob(ctx->qry.sha1, ctx->qry.path);
15}
16
17static void commit_fn(struct cgit_context *ctx)
18{
19 cgit_print_commit(ctx->qry.sha1);
20}
21
22static void diff_fn(struct cgit_context *ctx)
23{
24 cgit_print_diff(ctx->qry.sha1, ctx->qry.sha2, ctx->qry.path);
25}
26
27static void repolist_fn(struct cgit_context *ctx)
28{
29 cgit_print_repolist();
30}
31
32static void log_fn(struct cgit_context *ctx)
33{
34 cgit_print_log(ctx->qry.sha1, ctx->qry.ofs, ctx->cfg.max_commit_count,
35 ctx->qry.grep, ctx->qry.search, ctx->qry.path, 1);
36}
37
38static void patch_fn(struct cgit_context *ctx)
39{
40 cgit_print_patch(ctx->qry.sha1);
41}
42
43static void refs_fn(struct cgit_context *ctx)
44{
45 cgit_print_refs();
46}
47
48static void snapshot_fn(struct cgit_context *ctx)
49{
50 cgit_print_snapshot(ctx->qry.head, ctx->qry.sha1,
51 cgit_repobasename(ctx->repo->url), ctx->qry.path,
52 ctx->repo->snapshots);
53}
54
55static void summary_fn(struct cgit_context *ctx)
56{
57 cgit_print_summary();
58}
59
60static void tag_fn(struct cgit_context *ctx)
61{
62 cgit_print_tag(ctx->qry.sha1);
63}
64
65static void tree_fn(struct cgit_context *ctx)
66{
67 cgit_print_tree(ctx->qry.sha1, ctx->qry.path);
68}
69
70#define def_cmd(name, want_repo, want_layout) \
71 {#name, name##_fn, want_repo, want_layout}
72
73struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx)
74{
75 static struct cgit_cmd cmds[] = {
76 def_cmd(blob, 1, 0),
77 def_cmd(commit, 1, 1),
78 def_cmd(diff, 1, 1),
79 def_cmd(log, 1, 1),
80 def_cmd(patch, 1, 0),
81 def_cmd(refs, 1, 1),
82 def_cmd(repolist, 0, 0),
83 def_cmd(snapshot, 1, 0),
84 def_cmd(summary, 1, 1),
85 def_cmd(tag, 1, 1),
86 def_cmd(tree, 1, 1),
87 };
88 int i;
89
90 if (ctx->qry.page == NULL) {
91 if (ctx->repo)
92 ctx->qry.page = "summary";
93 else
94 ctx->qry.page = "repolist";
95 }
96
97 for(i = 0; i < sizeof(cmds)/sizeof(*cmds); i++)
98 if (!strcmp(ctx->qry.page, cmds[i].name))
99 return &cmds[i];
100 return NULL;
101}
diff --git a/cmd.h b/cmd.h
new file mode 100644
index 0000000..ec9e691
--- a/dev/null
+++ b/cmd.h
@@ -0,0 +1,15 @@
1#ifndef CMD_H
2#define CMD_H
3
4typedef void (*cgit_cmd_fn)(struct cgit_context *ctx);
5
6struct cgit_cmd {
7 const char *name;
8 cgit_cmd_fn fn;
9 unsigned int want_repo:1,
10 want_layout:1;
11};
12
13extern struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx);
14
15#endif /* CMD_H */
diff --git a/parsing.c b/parsing.c
index 027f06b..8dce488 100644
--- a/parsing.c
+++ b/parsing.c
@@ -77,193 +77,193 @@ int cgit_read_config(const char *filename, configfn fn)
77 return -1; 77 return -1;
78 nesting++; 78 nesting++;
79 while((len = read_config_line(f, line, &value, sizeof(line))) > 0) 79 while((len = read_config_line(f, line, &value, sizeof(line))) > 0)
80 (*fn)(line, value); 80 (*fn)(line, value);
81 nesting--; 81 nesting--;
82 fclose(f); 82 fclose(f);
83 return 0; 83 return 0;
84} 84}
85 85
86char *convert_query_hexchar(char *txt) 86char *convert_query_hexchar(char *txt)
87{ 87{
88 int d1, d2; 88 int d1, d2;
89 if (strlen(txt) < 3) { 89 if (strlen(txt) < 3) {
90 *txt = '\0'; 90 *txt = '\0';
91 return txt-1; 91 return txt-1;
92 } 92 }
93 d1 = hextoint(*(txt+1)); 93 d1 = hextoint(*(txt+1));
94 d2 = hextoint(*(txt+2)); 94 d2 = hextoint(*(txt+2));
95 if (d1<0 || d2<0) { 95 if (d1<0 || d2<0) {
96 strcpy(txt, txt+3); 96 strcpy(txt, txt+3);
97 return txt-1; 97 return txt-1;
98 } else { 98 } else {
99 *txt = d1 * 16 + d2; 99 *txt = d1 * 16 + d2;
100 strcpy(txt+1, txt+3); 100 strcpy(txt+1, txt+3);
101 return txt; 101 return txt;
102 } 102 }
103} 103}
104 104
105int cgit_parse_query(char *txt, configfn fn) 105int cgit_parse_query(char *txt, configfn fn)
106{ 106{
107 char *t, *value = NULL, c; 107 char *t, *value = NULL, c;
108 108
109 if (!txt) 109 if (!txt)
110 return 0; 110 return 0;
111 111
112 t = txt = xstrdup(txt); 112 t = txt = xstrdup(txt);
113 113
114 while((c=*t) != '\0') { 114 while((c=*t) != '\0') {
115 if (c=='=') { 115 if (c=='=') {
116 *t = '\0'; 116 *t = '\0';
117 value = t+1; 117 value = t+1;
118 } else if (c=='+') { 118 } else if (c=='+') {
119 *t = ' '; 119 *t = ' ';
120 } else if (c=='%') { 120 } else if (c=='%') {
121 t = convert_query_hexchar(t); 121 t = convert_query_hexchar(t);
122 } else if (c=='&') { 122 } else if (c=='&') {
123 *t = '\0'; 123 *t = '\0';
124 (*fn)(txt, value); 124 (*fn)(txt, value);
125 txt = t+1; 125 txt = t+1;
126 value = NULL; 126 value = NULL;
127 } 127 }
128 t++; 128 t++;
129 } 129 }
130 if (t!=txt) 130 if (t!=txt)
131 (*fn)(txt, value); 131 (*fn)(txt, value);
132 return 0; 132 return 0;
133} 133}
134 134
135/* 135/*
136 * url syntax: [repo ['/' cmd [ '/' path]]] 136 * url syntax: [repo ['/' cmd [ '/' path]]]
137 * repo: any valid repo url, may contain '/' 137 * repo: any valid repo url, may contain '/'
138 * cmd: log | commit | diff | tree | view | blob | snapshot 138 * cmd: log | commit | diff | tree | view | blob | snapshot
139 * path: any valid path, may contain '/' 139 * path: any valid path, may contain '/'
140 * 140 *
141 */ 141 */
142void cgit_parse_url(const char *url) 142void cgit_parse_url(const char *url)
143{ 143{
144 char *cmd, *p; 144 char *cmd, *p;
145 145
146 ctx.repo = NULL; 146 ctx.repo = NULL;
147 if (!url || url[0] == '\0') 147 if (!url || url[0] == '\0')
148 return; 148 return;
149 149
150 ctx.repo = cgit_get_repoinfo(url); 150 ctx.repo = cgit_get_repoinfo(url);
151 if (ctx.repo) { 151 if (ctx.repo) {
152 ctx.qry.repo = ctx.repo->url; 152 ctx.qry.repo = ctx.repo->url;
153 return; 153 return;
154 } 154 }
155 155
156 cmd = strchr(url, '/'); 156 cmd = strchr(url, '/');
157 while (!ctx.repo && cmd) { 157 while (!ctx.repo && cmd) {
158 cmd[0] = '\0'; 158 cmd[0] = '\0';
159 ctx.repo = cgit_get_repoinfo(url); 159 ctx.repo = cgit_get_repoinfo(url);
160 if (ctx.repo == NULL) { 160 if (ctx.repo == NULL) {
161 cmd[0] = '/'; 161 cmd[0] = '/';
162 cmd = strchr(cmd + 1, '/'); 162 cmd = strchr(cmd + 1, '/');
163 continue; 163 continue;
164 } 164 }
165 165
166 ctx.qry.repo = ctx.repo->url; 166 ctx.qry.repo = ctx.repo->url;
167 p = strchr(cmd + 1, '/'); 167 p = strchr(cmd + 1, '/');
168 if (p) { 168 if (p) {
169 p[0] = '\0'; 169 p[0] = '\0';
170 if (p[1]) 170 if (p[1])
171 ctx.qry.path = trim_end(p + 1, '/'); 171 ctx.qry.path = trim_end(p + 1, '/');
172 } 172 }
173 cgit_cmd = cgit_get_cmd_index(cmd + 1); 173 if (cmd[1])
174 ctx.qry.page = xstrdup(cmd + 1); 174 ctx.qry.page = xstrdup(cmd + 1);
175 return; 175 return;
176 } 176 }
177} 177}
178 178
179char *substr(const char *head, const char *tail) 179char *substr(const char *head, const char *tail)
180{ 180{
181 char *buf; 181 char *buf;
182 182
183 buf = xmalloc(tail - head + 1); 183 buf = xmalloc(tail - head + 1);
184 strncpy(buf, head, tail - head); 184 strncpy(buf, head, tail - head);
185 buf[tail - head] = '\0'; 185 buf[tail - head] = '\0';
186 return buf; 186 return buf;
187} 187}
188 188
189struct commitinfo *cgit_parse_commit(struct commit *commit) 189struct commitinfo *cgit_parse_commit(struct commit *commit)
190{ 190{
191 struct commitinfo *ret; 191 struct commitinfo *ret;
192 char *p = commit->buffer, *t = commit->buffer; 192 char *p = commit->buffer, *t = commit->buffer;
193 193
194 ret = xmalloc(sizeof(*ret)); 194 ret = xmalloc(sizeof(*ret));
195 ret->commit = commit; 195 ret->commit = commit;
196 ret->author = NULL; 196 ret->author = NULL;
197 ret->author_email = NULL; 197 ret->author_email = NULL;
198 ret->committer = NULL; 198 ret->committer = NULL;
199 ret->committer_email = NULL; 199 ret->committer_email = NULL;
200 ret->subject = NULL; 200 ret->subject = NULL;
201 ret->msg = NULL; 201 ret->msg = NULL;
202 ret->msg_encoding = NULL; 202 ret->msg_encoding = NULL;
203 203
204 if (p == NULL) 204 if (p == NULL)
205 return ret; 205 return ret;
206 206
207 if (strncmp(p, "tree ", 5)) 207 if (strncmp(p, "tree ", 5))
208 die("Bad commit: %s", sha1_to_hex(commit->object.sha1)); 208 die("Bad commit: %s", sha1_to_hex(commit->object.sha1));
209 else 209 else
210 p += 46; // "tree " + hex[40] + "\n" 210 p += 46; // "tree " + hex[40] + "\n"
211 211
212 while (!strncmp(p, "parent ", 7)) 212 while (!strncmp(p, "parent ", 7))
213 p += 48; // "parent " + hex[40] + "\n" 213 p += 48; // "parent " + hex[40] + "\n"
214 214
215 if (!strncmp(p, "author ", 7)) { 215 if (!strncmp(p, "author ", 7)) {
216 p += 7; 216 p += 7;
217 t = strchr(p, '<') - 1; 217 t = strchr(p, '<') - 1;
218 ret->author = substr(p, t); 218 ret->author = substr(p, t);
219 p = t; 219 p = t;
220 t = strchr(t, '>') + 1; 220 t = strchr(t, '>') + 1;
221 ret->author_email = substr(p, t); 221 ret->author_email = substr(p, t);
222 ret->author_date = atol(t+1); 222 ret->author_date = atol(t+1);
223 p = strchr(t, '\n') + 1; 223 p = strchr(t, '\n') + 1;
224 } 224 }
225 225
226 if (!strncmp(p, "committer ", 9)) { 226 if (!strncmp(p, "committer ", 9)) {
227 p += 9; 227 p += 9;
228 t = strchr(p, '<') - 1; 228 t = strchr(p, '<') - 1;
229 ret->committer = substr(p, t); 229 ret->committer = substr(p, t);
230 p = t; 230 p = t;
231 t = strchr(t, '>') + 1; 231 t = strchr(t, '>') + 1;
232 ret->committer_email = substr(p, t); 232 ret->committer_email = substr(p, t);
233 ret->committer_date = atol(t+1); 233 ret->committer_date = atol(t+1);
234 p = strchr(t, '\n') + 1; 234 p = strchr(t, '\n') + 1;
235 } 235 }
236 236
237 if (!strncmp(p, "encoding ", 9)) { 237 if (!strncmp(p, "encoding ", 9)) {
238 p += 9; 238 p += 9;
239 t = strchr(p, '\n') + 1; 239 t = strchr(p, '\n') + 1;
240 ret->msg_encoding = substr(p, t); 240 ret->msg_encoding = substr(p, t);
241 p = t; 241 p = t;
242 } else 242 } else
243 ret->msg_encoding = xstrdup(PAGE_ENCODING); 243 ret->msg_encoding = xstrdup(PAGE_ENCODING);
244 244
245 while (*p && (*p != '\n')) 245 while (*p && (*p != '\n'))
246 p = strchr(p, '\n') + 1; // skip unknown header fields 246 p = strchr(p, '\n') + 1; // skip unknown header fields
247 247
248 while (*p == '\n') 248 while (*p == '\n')
249 p = strchr(p, '\n') + 1; 249 p = strchr(p, '\n') + 1;
250 250
251 t = strchr(p, '\n'); 251 t = strchr(p, '\n');
252 if (t) { 252 if (t) {
253 if (*t == '\0') 253 if (*t == '\0')
254 ret->subject = "** empty **"; 254 ret->subject = "** empty **";
255 else 255 else
256 ret->subject = substr(p, t); 256 ret->subject = substr(p, t);
257 p = t + 1; 257 p = t + 1;
258 258
259 while (*p == '\n') 259 while (*p == '\n')
260 p = strchr(p, '\n') + 1; 260 p = strchr(p, '\n') + 1;
261 ret->msg = xstrdup(p); 261 ret->msg = xstrdup(p);
262 } else 262 } else
263 ret->subject = substr(p, p+strlen(p)); 263 ret->subject = substr(p, p+strlen(p));
264 264
265 if(strcmp(ret->msg_encoding, PAGE_ENCODING)) { 265 if(strcmp(ret->msg_encoding, PAGE_ENCODING)) {
266 t = reencode_string(ret->subject, PAGE_ENCODING, 266 t = reencode_string(ret->subject, PAGE_ENCODING,
267 ret->msg_encoding); 267 ret->msg_encoding);
268 if(t) { 268 if(t) {
269 free(ret->subject); 269 free(ret->subject);
diff --git a/shared.c b/shared.c
index 539d533..67eb67b 100644
--- a/shared.c
+++ b/shared.c
@@ -1,315 +1,302 @@
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 cgit_repolist cgit_repolist; 11struct cgit_repolist cgit_repolist;
12struct cgit_context ctx; 12struct cgit_context ctx;
13int cgit_cmd; 13int cgit_cmd;
14 14
15const char *cgit_version = CGIT_VERSION; 15const char *cgit_version = CGIT_VERSION;
16 16
17void cgit_prepare_context(struct cgit_context *ctx) 17void cgit_prepare_context(struct cgit_context *ctx)
18{ 18{
19 memset(ctx, 0, sizeof(ctx)); 19 memset(ctx, 0, sizeof(ctx));
20 ctx->cfg.agefile = "info/web/last-modified"; 20 ctx->cfg.agefile = "info/web/last-modified";
21 ctx->cfg.cache_dynamic_ttl = 5; 21 ctx->cfg.cache_dynamic_ttl = 5;
22 ctx->cfg.cache_max_create_time = 5; 22 ctx->cfg.cache_max_create_time = 5;
23 ctx->cfg.cache_repo_ttl = 5; 23 ctx->cfg.cache_repo_ttl = 5;
24 ctx->cfg.cache_root = CGIT_CACHE_ROOT; 24 ctx->cfg.cache_root = CGIT_CACHE_ROOT;
25 ctx->cfg.cache_root_ttl = 5; 25 ctx->cfg.cache_root_ttl = 5;
26 ctx->cfg.cache_static_ttl = -1; 26 ctx->cfg.cache_static_ttl = -1;
27 ctx->cfg.css = "/cgit.css"; 27 ctx->cfg.css = "/cgit.css";
28 ctx->cfg.logo = "/git-logo.png"; 28 ctx->cfg.logo = "/git-logo.png";
29 ctx->cfg.max_commit_count = 50; 29 ctx->cfg.max_commit_count = 50;
30 ctx->cfg.max_lock_attempts = 5; 30 ctx->cfg.max_lock_attempts = 5;
31 ctx->cfg.max_msg_len = 60; 31 ctx->cfg.max_msg_len = 60;
32 ctx->cfg.max_repodesc_len = 60; 32 ctx->cfg.max_repodesc_len = 60;
33 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 33 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
34 ctx->cfg.renamelimit = -1; 34 ctx->cfg.renamelimit = -1;
35 ctx->cfg.robots = "index, nofollow"; 35 ctx->cfg.robots = "index, nofollow";
36 ctx->cfg.root_title = "Git repository browser"; 36 ctx->cfg.root_title = "Git repository browser";
37 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 37 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
38 ctx->page.mimetype = "text/html"; 38 ctx->page.mimetype = "text/html";
39 ctx->page.charset = PAGE_ENCODING; 39 ctx->page.charset = PAGE_ENCODING;
40 ctx->page.filename = NULL; 40 ctx->page.filename = NULL;
41} 41}
42 42
43int cgit_get_cmd_index(const char *cmd)
44{
45 static char *cmds[] = {"log", "commit", "diff", "tree", "blob",
46 "snapshot", "tag", "refs", "patch", NULL};
47 int i;
48
49 for(i = 0; cmds[i]; i++)
50 if (!strcmp(cmd, cmds[i]))
51 return i + 1;
52 return 0;
53}
54
55int chk_zero(int result, char *msg) 43int chk_zero(int result, char *msg)
56{ 44{
57 if (result != 0) 45 if (result != 0)
58 die("%s: %s", msg, strerror(errno)); 46 die("%s: %s", msg, strerror(errno));
59 return result; 47 return result;
60} 48}
61 49
62int chk_positive(int result, char *msg) 50int chk_positive(int result, char *msg)
63{ 51{
64 if (result <= 0) 52 if (result <= 0)
65 die("%s: %s", msg, strerror(errno)); 53 die("%s: %s", msg, strerror(errno));
66 return result; 54 return result;
67} 55}
68 56
69int chk_non_negative(int result, char *msg) 57int chk_non_negative(int result, char *msg)
70{ 58{
71 if (result < 0) 59 if (result < 0)
72 die("%s: %s",msg, strerror(errno)); 60 die("%s: %s",msg, strerror(errno));
73 return result; 61 return result;
74} 62}
75 63
76struct cgit_repo *add_repo(const char *url) 64struct cgit_repo *add_repo(const char *url)
77{ 65{
78 struct cgit_repo *ret; 66 struct cgit_repo *ret;
79 67
80 if (++cgit_repolist.count > cgit_repolist.length) { 68 if (++cgit_repolist.count > cgit_repolist.length) {
81 if (cgit_repolist.length == 0) 69 if (cgit_repolist.length == 0)
82 cgit_repolist.length = 8; 70 cgit_repolist.length = 8;
83 else 71 else
84 cgit_repolist.length *= 2; 72 cgit_repolist.length *= 2;
85 cgit_repolist.repos = xrealloc(cgit_repolist.repos, 73 cgit_repolist.repos = xrealloc(cgit_repolist.repos,
86 cgit_repolist.length * 74 cgit_repolist.length *
87 sizeof(struct cgit_repo)); 75 sizeof(struct cgit_repo));
88 } 76 }
89 77
90 ret = &cgit_repolist.repos[cgit_repolist.count-1]; 78 ret = &cgit_repolist.repos[cgit_repolist.count-1];
91 ret->url = trim_end(url, '/'); 79 ret->url = trim_end(url, '/');
92 ret->name = ret->url; 80 ret->name = ret->url;
93 ret->path = NULL; 81 ret->path = NULL;
94 ret->desc = "[no description]"; 82 ret->desc = "[no description]";
95 ret->owner = NULL; 83 ret->owner = NULL;
96 ret->group = ctx.cfg.repo_group; 84 ret->group = ctx.cfg.repo_group;
97 ret->defbranch = "master"; 85 ret->defbranch = "master";
98 ret->snapshots = ctx.cfg.snapshots; 86 ret->snapshots = ctx.cfg.snapshots;
99 ret->enable_log_filecount = ctx.cfg.enable_log_filecount; 87 ret->enable_log_filecount = ctx.cfg.enable_log_filecount;
100 ret->enable_log_linecount = ctx.cfg.enable_log_linecount; 88 ret->enable_log_linecount = ctx.cfg.enable_log_linecount;
101 ret->module_link = ctx.cfg.module_link; 89 ret->module_link = ctx.cfg.module_link;
102 ret->readme = NULL; 90 ret->readme = NULL;
103 return ret; 91 return ret;
104} 92}
105 93
106struct cgit_repo *cgit_get_repoinfo(const char *url) 94struct cgit_repo *cgit_get_repoinfo(const char *url)
107{ 95{
108 int i; 96 int i;
109 struct cgit_repo *repo; 97 struct cgit_repo *repo;
110 98
111 for (i=0; i<cgit_repolist.count; i++) { 99 for (i=0; i<cgit_repolist.count; i++) {
112 repo = &cgit_repolist.repos[i]; 100 repo = &cgit_repolist.repos[i];
113 if (!strcmp(repo->url, url)) 101 if (!strcmp(repo->url, url))
114 return repo; 102 return repo;
115 } 103 }
116 return NULL; 104 return NULL;
117} 105}
118 106
119void cgit_global_config_cb(const char *name, const char *value) 107void cgit_global_config_cb(const char *name, const char *value)
120{ 108{
121 if (!strcmp(name, "root-title")) 109 if (!strcmp(name, "root-title"))
122 ctx.cfg.root_title = xstrdup(value); 110 ctx.cfg.root_title = xstrdup(value);
123 else if (!strcmp(name, "css")) 111 else if (!strcmp(name, "css"))
124 ctx.cfg.css = xstrdup(value); 112 ctx.cfg.css = xstrdup(value);
125 else if (!strcmp(name, "logo")) 113 else if (!strcmp(name, "logo"))
126 ctx.cfg.logo = xstrdup(value); 114 ctx.cfg.logo = xstrdup(value);
127 else if (!strcmp(name, "index-header")) 115 else if (!strcmp(name, "index-header"))
128 ctx.cfg.index_header = xstrdup(value); 116 ctx.cfg.index_header = xstrdup(value);
129 else if (!strcmp(name, "index-info")) 117 else if (!strcmp(name, "index-info"))
130 ctx.cfg.index_info = xstrdup(value); 118 ctx.cfg.index_info = xstrdup(value);
131 else if (!strcmp(name, "logo-link")) 119 else if (!strcmp(name, "logo-link"))
132 ctx.cfg.logo_link = xstrdup(value); 120 ctx.cfg.logo_link = xstrdup(value);
133 else if (!strcmp(name, "module-link")) 121 else if (!strcmp(name, "module-link"))
134 ctx.cfg.module_link = xstrdup(value); 122 ctx.cfg.module_link = xstrdup(value);
135 else if (!strcmp(name, "virtual-root")) { 123 else if (!strcmp(name, "virtual-root")) {
136 ctx.cfg.virtual_root = trim_end(value, '/'); 124 ctx.cfg.virtual_root = trim_end(value, '/');
137 if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) 125 if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
138 ctx.cfg.virtual_root = ""; 126 ctx.cfg.virtual_root = "";
139 } else if (!strcmp(name, "nocache")) 127 } else if (!strcmp(name, "nocache"))
140 ctx.cfg.nocache = atoi(value); 128 ctx.cfg.nocache = atoi(value);
141 else if (!strcmp(name, "snapshots")) 129 else if (!strcmp(name, "snapshots"))
142 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); 130 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
143 else if (!strcmp(name, "enable-index-links")) 131 else if (!strcmp(name, "enable-index-links"))
144 ctx.cfg.enable_index_links = atoi(value); 132 ctx.cfg.enable_index_links = atoi(value);
145 else if (!strcmp(name, "enable-log-filecount")) 133 else if (!strcmp(name, "enable-log-filecount"))
146 ctx.cfg.enable_log_filecount = atoi(value); 134 ctx.cfg.enable_log_filecount = atoi(value);
147 else if (!strcmp(name, "enable-log-linecount")) 135 else if (!strcmp(name, "enable-log-linecount"))
148 ctx.cfg.enable_log_linecount = atoi(value); 136 ctx.cfg.enable_log_linecount = atoi(value);
149 else if (!strcmp(name, "cache-root")) 137 else if (!strcmp(name, "cache-root"))
150 ctx.cfg.cache_root = xstrdup(value); 138 ctx.cfg.cache_root = xstrdup(value);
151 else if (!strcmp(name, "cache-root-ttl")) 139 else if (!strcmp(name, "cache-root-ttl"))
152 ctx.cfg.cache_root_ttl = atoi(value); 140 ctx.cfg.cache_root_ttl = atoi(value);
153 else if (!strcmp(name, "cache-repo-ttl")) 141 else if (!strcmp(name, "cache-repo-ttl"))
154 ctx.cfg.cache_repo_ttl = atoi(value); 142 ctx.cfg.cache_repo_ttl = atoi(value);
155 else if (!strcmp(name, "cache-static-ttl")) 143 else if (!strcmp(name, "cache-static-ttl"))
156 ctx.cfg.cache_static_ttl = atoi(value); 144 ctx.cfg.cache_static_ttl = atoi(value);
157 else if (!strcmp(name, "cache-dynamic-ttl")) 145 else if (!strcmp(name, "cache-dynamic-ttl"))
158 ctx.cfg.cache_dynamic_ttl = atoi(value); 146 ctx.cfg.cache_dynamic_ttl = atoi(value);
159 else if (!strcmp(name, "max-message-length")) 147 else if (!strcmp(name, "max-message-length"))
160 ctx.cfg.max_msg_len = atoi(value); 148 ctx.cfg.max_msg_len = atoi(value);
161 else if (!strcmp(name, "max-repodesc-length")) 149 else if (!strcmp(name, "max-repodesc-length"))
162 ctx.cfg.max_repodesc_len = atoi(value); 150 ctx.cfg.max_repodesc_len = atoi(value);
163 else if (!strcmp(name, "max-commit-count")) 151 else if (!strcmp(name, "max-commit-count"))
164 ctx.cfg.max_commit_count = atoi(value); 152 ctx.cfg.max_commit_count = atoi(value);
165 else if (!strcmp(name, "summary-log")) 153 else if (!strcmp(name, "summary-log"))
166 ctx.cfg.summary_log = atoi(value); 154 ctx.cfg.summary_log = atoi(value);
167 else if (!strcmp(name, "summary-branches")) 155 else if (!strcmp(name, "summary-branches"))
168 ctx.cfg.summary_branches = atoi(value); 156 ctx.cfg.summary_branches = atoi(value);
169 else if (!strcmp(name, "summary-tags")) 157 else if (!strcmp(name, "summary-tags"))
170 ctx.cfg.summary_tags = atoi(value); 158 ctx.cfg.summary_tags = atoi(value);
171 else if (!strcmp(name, "agefile")) 159 else if (!strcmp(name, "agefile"))
172 ctx.cfg.agefile = xstrdup(value); 160 ctx.cfg.agefile = xstrdup(value);
173 else if (!strcmp(name, "renamelimit")) 161 else if (!strcmp(name, "renamelimit"))
174 ctx.cfg.renamelimit = atoi(value); 162 ctx.cfg.renamelimit = atoi(value);
175 else if (!strcmp(name, "robots")) 163 else if (!strcmp(name, "robots"))
176 ctx.cfg.robots = xstrdup(value); 164 ctx.cfg.robots = xstrdup(value);
177 else if (!strcmp(name, "clone-prefix")) 165 else if (!strcmp(name, "clone-prefix"))
178 ctx.cfg.clone_prefix = xstrdup(value); 166 ctx.cfg.clone_prefix = xstrdup(value);
179 else if (!strcmp(name, "repo.group")) 167 else if (!strcmp(name, "repo.group"))
180 ctx.cfg.repo_group = xstrdup(value); 168 ctx.cfg.repo_group = xstrdup(value);
181 else if (!strcmp(name, "repo.url")) 169 else if (!strcmp(name, "repo.url"))
182 ctx.repo = add_repo(value); 170 ctx.repo = add_repo(value);
183 else if (!strcmp(name, "repo.name")) 171 else if (!strcmp(name, "repo.name"))
184 ctx.repo->name = xstrdup(value); 172 ctx.repo->name = xstrdup(value);
185 else if (ctx.repo && !strcmp(name, "repo.path")) 173 else if (ctx.repo && !strcmp(name, "repo.path"))
186 ctx.repo->path = trim_end(value, '/'); 174 ctx.repo->path = trim_end(value, '/');
187 else if (ctx.repo && !strcmp(name, "repo.clone-url")) 175 else if (ctx.repo && !strcmp(name, "repo.clone-url"))
188 ctx.repo->clone_url = xstrdup(value); 176 ctx.repo->clone_url = xstrdup(value);
189 else if (ctx.repo && !strcmp(name, "repo.desc")) 177 else if (ctx.repo && !strcmp(name, "repo.desc"))
190 ctx.repo->desc = xstrdup(value); 178 ctx.repo->desc = xstrdup(value);
191 else if (ctx.repo && !strcmp(name, "repo.owner")) 179 else if (ctx.repo && !strcmp(name, "repo.owner"))
192 ctx.repo->owner = xstrdup(value); 180 ctx.repo->owner = xstrdup(value);
193 else if (ctx.repo && !strcmp(name, "repo.defbranch")) 181 else if (ctx.repo && !strcmp(name, "repo.defbranch"))
194 ctx.repo->defbranch = xstrdup(value); 182 ctx.repo->defbranch = xstrdup(value);
195 else if (ctx.repo && !strcmp(name, "repo.snapshots")) 183 else if (ctx.repo && !strcmp(name, "repo.snapshots"))
196 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ 184 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
197 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) 185 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount"))
198 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 186 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
199 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) 187 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount"))
200 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 188 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
201 else if (ctx.repo && !strcmp(name, "repo.module-link")) 189 else if (ctx.repo && !strcmp(name, "repo.module-link"))
202 ctx.repo->module_link= xstrdup(value); 190 ctx.repo->module_link= xstrdup(value);
203 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { 191 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
204 if (*value == '/') 192 if (*value == '/')
205 ctx.repo->readme = xstrdup(value); 193 ctx.repo->readme = xstrdup(value);
206 else 194 else
207 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); 195 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value));
208 } else if (!strcmp(name, "include")) 196 } else if (!strcmp(name, "include"))
209 cgit_read_config(value, cgit_global_config_cb); 197 cgit_read_config(value, cgit_global_config_cb);
210} 198}
211 199
212void cgit_querystring_cb(const char *name, const char *value) 200void cgit_querystring_cb(const char *name, const char *value)
213{ 201{
214 if (!strcmp(name,"r")) { 202 if (!strcmp(name,"r")) {
215 ctx.qry.repo = xstrdup(value); 203 ctx.qry.repo = xstrdup(value);
216 ctx.repo = cgit_get_repoinfo(value); 204 ctx.repo = cgit_get_repoinfo(value);
217 } else if (!strcmp(name, "p")) { 205 } else if (!strcmp(name, "p")) {
218 ctx.qry.page = xstrdup(value); 206 ctx.qry.page = xstrdup(value);
219 cgit_cmd = cgit_get_cmd_index(value);
220 } else if (!strcmp(name, "url")) { 207 } else if (!strcmp(name, "url")) {
221 cgit_parse_url(value); 208 cgit_parse_url(value);
222 } else if (!strcmp(name, "qt")) { 209 } else if (!strcmp(name, "qt")) {
223 ctx.qry.grep = xstrdup(value); 210 ctx.qry.grep = xstrdup(value);
224 } else if (!strcmp(name, "q")) { 211 } else if (!strcmp(name, "q")) {
225 ctx.qry.search = xstrdup(value); 212 ctx.qry.search = xstrdup(value);
226 } else if (!strcmp(name, "h")) { 213 } else if (!strcmp(name, "h")) {
227 ctx.qry.head = xstrdup(value); 214 ctx.qry.head = xstrdup(value);
228 ctx.qry.has_symref = 1; 215 ctx.qry.has_symref = 1;
229 } else if (!strcmp(name, "id")) { 216 } else if (!strcmp(name, "id")) {
230 ctx.qry.sha1 = xstrdup(value); 217 ctx.qry.sha1 = xstrdup(value);
231 ctx.qry.has_sha1 = 1; 218 ctx.qry.has_sha1 = 1;
232 } else if (!strcmp(name, "id2")) { 219 } else if (!strcmp(name, "id2")) {
233 ctx.qry.sha2 = xstrdup(value); 220 ctx.qry.sha2 = xstrdup(value);
234 ctx.qry.has_sha1 = 1; 221 ctx.qry.has_sha1 = 1;
235 } else if (!strcmp(name, "ofs")) { 222 } else if (!strcmp(name, "ofs")) {
236 ctx.qry.ofs = atoi(value); 223 ctx.qry.ofs = atoi(value);
237 } else if (!strcmp(name, "path")) { 224 } else if (!strcmp(name, "path")) {
238 ctx.qry.path = trim_end(value, '/'); 225 ctx.qry.path = trim_end(value, '/');
239 } else if (!strcmp(name, "name")) { 226 } else if (!strcmp(name, "name")) {
240 ctx.qry.name = xstrdup(value); 227 ctx.qry.name = xstrdup(value);
241 } 228 }
242} 229}
243 230
244void *cgit_free_commitinfo(struct commitinfo *info) 231void *cgit_free_commitinfo(struct commitinfo *info)
245{ 232{
246 free(info->author); 233 free(info->author);
247 free(info->author_email); 234 free(info->author_email);
248 free(info->committer); 235 free(info->committer);
249 free(info->committer_email); 236 free(info->committer_email);
250 free(info->subject); 237 free(info->subject);
251 free(info->msg); 238 free(info->msg);
252 free(info->msg_encoding); 239 free(info->msg_encoding);
253 free(info); 240 free(info);
254 return NULL; 241 return NULL;
255} 242}
256 243
257int hextoint(char c) 244int hextoint(char c)
258{ 245{
259 if (c >= 'a' && c <= 'f') 246 if (c >= 'a' && c <= 'f')
260 return 10 + c - 'a'; 247 return 10 + c - 'a';
261 else if (c >= 'A' && c <= 'F') 248 else if (c >= 'A' && c <= 'F')
262 return 10 + c - 'A'; 249 return 10 + c - 'A';
263 else if (c >= '0' && c <= '9') 250 else if (c >= '0' && c <= '9')
264 return c - '0'; 251 return c - '0';
265 else 252 else
266 return -1; 253 return -1;
267} 254}
268 255
269char *trim_end(const char *str, char c) 256char *trim_end(const char *str, char c)
270{ 257{
271 int len; 258 int len;
272 char *s, *t; 259 char *s, *t;
273 260
274 if (str == NULL) 261 if (str == NULL)
275 return NULL; 262 return NULL;
276 t = (char *)str; 263 t = (char *)str;
277 len = strlen(t); 264 len = strlen(t);
278 while(len > 0 && t[len - 1] == c) 265 while(len > 0 && t[len - 1] == c)
279 len--; 266 len--;
280 267
281 if (len == 0) 268 if (len == 0)
282 return NULL; 269 return NULL;
283 270
284 c = t[len]; 271 c = t[len];
285 t[len] = '\0'; 272 t[len] = '\0';
286 s = xstrdup(t); 273 s = xstrdup(t);
287 t[len] = c; 274 t[len] = c;
288 return s; 275 return s;
289} 276}
290 277
291char *strlpart(char *txt, int maxlen) 278char *strlpart(char *txt, int maxlen)
292{ 279{
293 char *result; 280 char *result;
294 281
295 if (!txt) 282 if (!txt)
296 return txt; 283 return txt;
297 284
298 if (strlen(txt) <= maxlen) 285 if (strlen(txt) <= maxlen)
299 return txt; 286 return txt;
300 result = xmalloc(maxlen + 1); 287 result = xmalloc(maxlen + 1);
301 memcpy(result, txt, maxlen - 3); 288 memcpy(result, txt, maxlen - 3);
302 result[maxlen-1] = result[maxlen-2] = result[maxlen-3] = '.'; 289 result[maxlen-1] = result[maxlen-2] = result[maxlen-3] = '.';
303 result[maxlen] = '\0'; 290 result[maxlen] = '\0';
304 return result; 291 return result;
305} 292}
306 293
307char *strrpart(char *txt, int maxlen) 294char *strrpart(char *txt, int maxlen)
308{ 295{
309 char *result; 296 char *result;
310 297
311 if (!txt) 298 if (!txt)
312 return txt; 299 return txt;
313 300
314 if (strlen(txt) <= maxlen) 301 if (strlen(txt) <= maxlen)
315 return txt; 302 return txt;