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,43 +1,43 @@
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
diff --git a/cgit.c b/cgit.c
index a83f0be..79e0e43 100644
--- a/cgit.c
+++ b/cgit.c
@@ -60,180 +60,150 @@ int find_current_ref(const char *refname, const unsigned char *sha1,
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)) {
diff --git a/cgit.h b/cgit.h
index 40e2d40..295441b 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,59 +1,46 @@
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);
@@ -176,49 +163,48 @@ struct cgit_config {
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
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
@@ -149,49 +149,49 @@ void cgit_parse_url(const char *url)
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;
diff --git a/shared.c b/shared.c
index 539d533..67eb67b 100644
--- a/shared.c
+++ b/shared.c
@@ -19,60 +19,48 @@ void cgit_prepare_context(struct cgit_context *ctx)
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;
@@ -195,49 +183,48 @@ void cgit_global_config_cb(const char *name, const char *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