summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--Makefile2
-rw-r--r--cgit.c3
-rw-r--r--cgit.css6
-rw-r--r--cgit.h1
-rw-r--r--cgitrc.5.txt4
m---------git0
-rw-r--r--ui-commit.c2
-rw-r--r--ui-log.c2
-rw-r--r--ui-plain.c3
-rw-r--r--ui-tree.c35
10 files changed, 37 insertions, 21 deletions
diff --git a/Makefile b/Makefile
index 1f9893a..dc9dffd 100644
--- a/Makefile
+++ b/Makefile
@@ -1,56 +1,56 @@
1CGIT_VERSION = v0.8.2.1 1CGIT_VERSION = v0.8.2.1
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_DATA_PATH = $(CGIT_SCRIPT_PATH) 4CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH)
5CGIT_CONFIG = /etc/cgitrc 5CGIT_CONFIG = /etc/cgitrc
6CACHE_ROOT = /var/cache/cgit 6CACHE_ROOT = /var/cache/cgit
7SHA1_HEADER = <openssl/sha.h> 7SHA1_HEADER = <openssl/sha.h>
8GIT_VER = 1.6.3.4 8GIT_VER = 1.6.4.3
9GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 9GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2
10INSTALL = install 10INSTALL = install
11 11
12# Define NO_STRCASESTR if you don't have strcasestr. 12# Define NO_STRCASESTR if you don't have strcasestr.
13# 13#
14# Define NEEDS_LIBICONV if linking with libc is not enough (eg. Darwin). 14# Define NEEDS_LIBICONV if linking with libc is not enough (eg. Darwin).
15# 15#
16 16
17#-include config.mak 17#-include config.mak
18 18
19# 19#
20# Platform specific tweaks 20# Platform specific tweaks
21# 21#
22 22
23uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') 23uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
24uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') 24uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
25uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') 25uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
26 26
27ifeq ($(uname_O),Cygwin) 27ifeq ($(uname_O),Cygwin)
28 NO_STRCASESTR = YesPlease 28 NO_STRCASESTR = YesPlease
29 NEEDS_LIBICONV = YesPlease 29 NEEDS_LIBICONV = YesPlease
30endif 30endif
31 31
32# 32#
33# Let the user override the above settings. 33# Let the user override the above settings.
34# 34#
35-include cgit.conf 35-include cgit.conf
36 36
37# 37#
38# Define a way to invoke make in subdirs quietly, shamelessly ripped 38# Define a way to invoke make in subdirs quietly, shamelessly ripped
39# from git.git 39# from git.git
40# 40#
41QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir 41QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
42QUIET_SUBDIR1 = 42QUIET_SUBDIR1 =
43 43
44ifneq ($(findstring $(MAKEFLAGS),w),w) 44ifneq ($(findstring $(MAKEFLAGS),w),w)
45PRINT_DIR = --no-print-directory 45PRINT_DIR = --no-print-directory
46else # "make -w" 46else # "make -w"
47NO_SUBDIR = : 47NO_SUBDIR = :
48endif 48endif
49 49
50ifndef V 50ifndef V
51 QUIET_CC = @echo ' ' CC $@; 51 QUIET_CC = @echo ' ' CC $@;
52 QUIET_MM = @echo ' ' MM $@; 52 QUIET_MM = @echo ' ' MM $@;
53 QUIET_SUBDIR0 = +@subdir= 53 QUIET_SUBDIR0 = +@subdir=
54 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ 54 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
55 $(MAKE) $(PRINT_DIR) -C $$subdir 55 $(MAKE) $(PRINT_DIR) -C $$subdir
56endif 56endif
diff --git a/cgit.c b/cgit.c
index 3fcca2a..bd37788 100644
--- a/cgit.c
+++ b/cgit.c
@@ -92,96 +92,98 @@ void config_cb(const char *name, const char *value)
92 else if (ctx.repo && !prefixcmp(name, "repo.")) 92 else if (ctx.repo && !prefixcmp(name, "repo."))
93 repo_config(ctx.repo, name + 5, value); 93 repo_config(ctx.repo, name + 5, value);
94 else if (!strcmp(name, "root-title")) 94 else if (!strcmp(name, "root-title"))
95 ctx.cfg.root_title = xstrdup(value); 95 ctx.cfg.root_title = xstrdup(value);
96 else if (!strcmp(name, "root-desc")) 96 else if (!strcmp(name, "root-desc"))
97 ctx.cfg.root_desc = xstrdup(value); 97 ctx.cfg.root_desc = xstrdup(value);
98 else if (!strcmp(name, "root-readme")) 98 else if (!strcmp(name, "root-readme"))
99 ctx.cfg.root_readme = xstrdup(value); 99 ctx.cfg.root_readme = xstrdup(value);
100 else if (!strcmp(name, "css")) 100 else if (!strcmp(name, "css"))
101 ctx.cfg.css = xstrdup(value); 101 ctx.cfg.css = xstrdup(value);
102 else if (!strcmp(name, "favicon")) 102 else if (!strcmp(name, "favicon"))
103 ctx.cfg.favicon = xstrdup(value); 103 ctx.cfg.favicon = xstrdup(value);
104 else if (!strcmp(name, "footer")) 104 else if (!strcmp(name, "footer"))
105 ctx.cfg.footer = xstrdup(value); 105 ctx.cfg.footer = xstrdup(value);
106 else if (!strcmp(name, "head-include")) 106 else if (!strcmp(name, "head-include"))
107 ctx.cfg.head_include = xstrdup(value); 107 ctx.cfg.head_include = xstrdup(value);
108 else if (!strcmp(name, "header")) 108 else if (!strcmp(name, "header"))
109 ctx.cfg.header = xstrdup(value); 109 ctx.cfg.header = xstrdup(value);
110 else if (!strcmp(name, "logo")) 110 else if (!strcmp(name, "logo"))
111 ctx.cfg.logo = xstrdup(value); 111 ctx.cfg.logo = xstrdup(value);
112 else if (!strcmp(name, "index-header")) 112 else if (!strcmp(name, "index-header"))
113 ctx.cfg.index_header = xstrdup(value); 113 ctx.cfg.index_header = xstrdup(value);
114 else if (!strcmp(name, "index-info")) 114 else if (!strcmp(name, "index-info"))
115 ctx.cfg.index_info = xstrdup(value); 115 ctx.cfg.index_info = xstrdup(value);
116 else if (!strcmp(name, "logo-link")) 116 else if (!strcmp(name, "logo-link"))
117 ctx.cfg.logo_link = xstrdup(value); 117 ctx.cfg.logo_link = xstrdup(value);
118 else if (!strcmp(name, "module-link")) 118 else if (!strcmp(name, "module-link"))
119 ctx.cfg.module_link = xstrdup(value); 119 ctx.cfg.module_link = xstrdup(value);
120 else if (!strcmp(name, "virtual-root")) { 120 else if (!strcmp(name, "virtual-root")) {
121 ctx.cfg.virtual_root = trim_end(value, '/'); 121 ctx.cfg.virtual_root = trim_end(value, '/');
122 if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) 122 if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
123 ctx.cfg.virtual_root = ""; 123 ctx.cfg.virtual_root = "";
124 } else if (!strcmp(name, "nocache")) 124 } else if (!strcmp(name, "nocache"))
125 ctx.cfg.nocache = atoi(value); 125 ctx.cfg.nocache = atoi(value);
126 else if (!strcmp(name, "noplainemail")) 126 else if (!strcmp(name, "noplainemail"))
127 ctx.cfg.noplainemail = atoi(value); 127 ctx.cfg.noplainemail = atoi(value);
128 else if (!strcmp(name, "noheader")) 128 else if (!strcmp(name, "noheader"))
129 ctx.cfg.noheader = atoi(value); 129 ctx.cfg.noheader = atoi(value);
130 else if (!strcmp(name, "snapshots")) 130 else if (!strcmp(name, "snapshots"))
131 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); 131 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
132 else if (!strcmp(name, "enable-filter-overrides")) 132 else if (!strcmp(name, "enable-filter-overrides"))
133 ctx.cfg.enable_filter_overrides = atoi(value); 133 ctx.cfg.enable_filter_overrides = atoi(value);
134 else if (!strcmp(name, "enable-index-links")) 134 else if (!strcmp(name, "enable-index-links"))
135 ctx.cfg.enable_index_links = atoi(value); 135 ctx.cfg.enable_index_links = atoi(value);
136 else if (!strcmp(name, "enable-log-filecount")) 136 else if (!strcmp(name, "enable-log-filecount"))
137 ctx.cfg.enable_log_filecount = atoi(value); 137 ctx.cfg.enable_log_filecount = atoi(value);
138 else if (!strcmp(name, "enable-log-linecount")) 138 else if (!strcmp(name, "enable-log-linecount"))
139 ctx.cfg.enable_log_linecount = atoi(value); 139 ctx.cfg.enable_log_linecount = atoi(value);
140 else if (!strcmp(name, "enable-tree-linenumbers"))
141 ctx.cfg.enable_tree_linenumbers = atoi(value);
140 else if (!strcmp(name, "max-stats")) 142 else if (!strcmp(name, "max-stats"))
141 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); 143 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL);
142 else if (!strcmp(name, "cache-size")) 144 else if (!strcmp(name, "cache-size"))
143 ctx.cfg.cache_size = atoi(value); 145 ctx.cfg.cache_size = atoi(value);
144 else if (!strcmp(name, "cache-root")) 146 else if (!strcmp(name, "cache-root"))
145 ctx.cfg.cache_root = xstrdup(value); 147 ctx.cfg.cache_root = xstrdup(value);
146 else if (!strcmp(name, "cache-root-ttl")) 148 else if (!strcmp(name, "cache-root-ttl"))
147 ctx.cfg.cache_root_ttl = atoi(value); 149 ctx.cfg.cache_root_ttl = atoi(value);
148 else if (!strcmp(name, "cache-repo-ttl")) 150 else if (!strcmp(name, "cache-repo-ttl"))
149 ctx.cfg.cache_repo_ttl = atoi(value); 151 ctx.cfg.cache_repo_ttl = atoi(value);
150 else if (!strcmp(name, "cache-scanrc-ttl")) 152 else if (!strcmp(name, "cache-scanrc-ttl"))
151 ctx.cfg.cache_scanrc_ttl = atoi(value); 153 ctx.cfg.cache_scanrc_ttl = atoi(value);
152 else if (!strcmp(name, "cache-static-ttl")) 154 else if (!strcmp(name, "cache-static-ttl"))
153 ctx.cfg.cache_static_ttl = atoi(value); 155 ctx.cfg.cache_static_ttl = atoi(value);
154 else if (!strcmp(name, "cache-dynamic-ttl")) 156 else if (!strcmp(name, "cache-dynamic-ttl"))
155 ctx.cfg.cache_dynamic_ttl = atoi(value); 157 ctx.cfg.cache_dynamic_ttl = atoi(value);
156 else if (!strcmp(name, "about-filter")) 158 else if (!strcmp(name, "about-filter"))
157 ctx.cfg.about_filter = new_filter(value, 0); 159 ctx.cfg.about_filter = new_filter(value, 0);
158 else if (!strcmp(name, "commit-filter")) 160 else if (!strcmp(name, "commit-filter"))
159 ctx.cfg.commit_filter = new_filter(value, 0); 161 ctx.cfg.commit_filter = new_filter(value, 0);
160 else if (!strcmp(name, "embedded")) 162 else if (!strcmp(name, "embedded"))
161 ctx.cfg.embedded = atoi(value); 163 ctx.cfg.embedded = atoi(value);
162 else if (!strcmp(name, "max-message-length")) 164 else if (!strcmp(name, "max-message-length"))
163 ctx.cfg.max_msg_len = atoi(value); 165 ctx.cfg.max_msg_len = atoi(value);
164 else if (!strcmp(name, "max-repodesc-length")) 166 else if (!strcmp(name, "max-repodesc-length"))
165 ctx.cfg.max_repodesc_len = atoi(value); 167 ctx.cfg.max_repodesc_len = atoi(value);
166 else if (!strcmp(name, "max-repo-count")) 168 else if (!strcmp(name, "max-repo-count"))
167 ctx.cfg.max_repo_count = atoi(value); 169 ctx.cfg.max_repo_count = atoi(value);
168 else if (!strcmp(name, "max-commit-count")) 170 else if (!strcmp(name, "max-commit-count"))
169 ctx.cfg.max_commit_count = atoi(value); 171 ctx.cfg.max_commit_count = atoi(value);
170 else if (!strcmp(name, "scan-path")) 172 else if (!strcmp(name, "scan-path"))
171 if (!ctx.cfg.nocache && ctx.cfg.cache_size) 173 if (!ctx.cfg.nocache && ctx.cfg.cache_size)
172 process_cached_repolist(value); 174 process_cached_repolist(value);
173 else 175 else
174 scan_tree(value, repo_config); 176 scan_tree(value, repo_config);
175 else if (!strcmp(name, "source-filter")) 177 else if (!strcmp(name, "source-filter"))
176 ctx.cfg.source_filter = new_filter(value, 1); 178 ctx.cfg.source_filter = new_filter(value, 1);
177 else if (!strcmp(name, "summary-log")) 179 else if (!strcmp(name, "summary-log"))
178 ctx.cfg.summary_log = atoi(value); 180 ctx.cfg.summary_log = atoi(value);
179 else if (!strcmp(name, "summary-branches")) 181 else if (!strcmp(name, "summary-branches"))
180 ctx.cfg.summary_branches = atoi(value); 182 ctx.cfg.summary_branches = atoi(value);
181 else if (!strcmp(name, "summary-tags")) 183 else if (!strcmp(name, "summary-tags"))
182 ctx.cfg.summary_tags = atoi(value); 184 ctx.cfg.summary_tags = atoi(value);
183 else if (!strcmp(name, "agefile")) 185 else if (!strcmp(name, "agefile"))
184 ctx.cfg.agefile = xstrdup(value); 186 ctx.cfg.agefile = xstrdup(value);
185 else if (!strcmp(name, "renamelimit")) 187 else if (!strcmp(name, "renamelimit"))
186 ctx.cfg.renamelimit = atoi(value); 188 ctx.cfg.renamelimit = atoi(value);
187 else if (!strcmp(name, "robots")) 189 else if (!strcmp(name, "robots"))
@@ -215,96 +217,97 @@ static void querystring_cb(const char *name, const char *value)
215 ctx.qry.search = xstrdup(value); 217 ctx.qry.search = xstrdup(value);
216 } else if (!strcmp(name, "h")) { 218 } else if (!strcmp(name, "h")) {
217 ctx.qry.head = xstrdup(value); 219 ctx.qry.head = xstrdup(value);
218 ctx.qry.has_symref = 1; 220 ctx.qry.has_symref = 1;
219 } else if (!strcmp(name, "id")) { 221 } else if (!strcmp(name, "id")) {
220 ctx.qry.sha1 = xstrdup(value); 222 ctx.qry.sha1 = xstrdup(value);
221 ctx.qry.has_sha1 = 1; 223 ctx.qry.has_sha1 = 1;
222 } else if (!strcmp(name, "id2")) { 224 } else if (!strcmp(name, "id2")) {
223 ctx.qry.sha2 = xstrdup(value); 225 ctx.qry.sha2 = xstrdup(value);
224 ctx.qry.has_sha1 = 1; 226 ctx.qry.has_sha1 = 1;
225 } else if (!strcmp(name, "ofs")) { 227 } else if (!strcmp(name, "ofs")) {
226 ctx.qry.ofs = atoi(value); 228 ctx.qry.ofs = atoi(value);
227 } else if (!strcmp(name, "path")) { 229 } else if (!strcmp(name, "path")) {
228 ctx.qry.path = trim_end(value, '/'); 230 ctx.qry.path = trim_end(value, '/');
229 } else if (!strcmp(name, "name")) { 231 } else if (!strcmp(name, "name")) {
230 ctx.qry.name = xstrdup(value); 232 ctx.qry.name = xstrdup(value);
231 } else if (!strcmp(name, "mimetype")) { 233 } else if (!strcmp(name, "mimetype")) {
232 ctx.qry.mimetype = xstrdup(value); 234 ctx.qry.mimetype = xstrdup(value);
233 } else if (!strcmp(name, "s")){ 235 } else if (!strcmp(name, "s")){
234 ctx.qry.sort = xstrdup(value); 236 ctx.qry.sort = xstrdup(value);
235 } else if (!strcmp(name, "showmsg")) { 237 } else if (!strcmp(name, "showmsg")) {
236 ctx.qry.showmsg = atoi(value); 238 ctx.qry.showmsg = atoi(value);
237 } else if (!strcmp(name, "period")) { 239 } else if (!strcmp(name, "period")) {
238 ctx.qry.period = xstrdup(value); 240 ctx.qry.period = xstrdup(value);
239 } 241 }
240} 242}
241 243
242char *xstrdupn(const char *str) 244char *xstrdupn(const char *str)
243{ 245{
244 return (str ? xstrdup(str) : NULL); 246 return (str ? xstrdup(str) : NULL);
245} 247}
246 248
247static void prepare_context(struct cgit_context *ctx) 249static void prepare_context(struct cgit_context *ctx)
248{ 250{
249 memset(ctx, 0, sizeof(ctx)); 251 memset(ctx, 0, sizeof(ctx));
250 ctx->cfg.agefile = "info/web/last-modified"; 252 ctx->cfg.agefile = "info/web/last-modified";
251 ctx->cfg.nocache = 0; 253 ctx->cfg.nocache = 0;
252 ctx->cfg.cache_size = 0; 254 ctx->cfg.cache_size = 0;
253 ctx->cfg.cache_dynamic_ttl = 5; 255 ctx->cfg.cache_dynamic_ttl = 5;
254 ctx->cfg.cache_max_create_time = 5; 256 ctx->cfg.cache_max_create_time = 5;
255 ctx->cfg.cache_repo_ttl = 5; 257 ctx->cfg.cache_repo_ttl = 5;
256 ctx->cfg.cache_root = CGIT_CACHE_ROOT; 258 ctx->cfg.cache_root = CGIT_CACHE_ROOT;
257 ctx->cfg.cache_root_ttl = 5; 259 ctx->cfg.cache_root_ttl = 5;
258 ctx->cfg.cache_scanrc_ttl = 15; 260 ctx->cfg.cache_scanrc_ttl = 15;
259 ctx->cfg.cache_static_ttl = -1; 261 ctx->cfg.cache_static_ttl = -1;
260 ctx->cfg.css = "/cgit.css"; 262 ctx->cfg.css = "/cgit.css";
261 ctx->cfg.logo = "/cgit.png"; 263 ctx->cfg.logo = "/cgit.png";
262 ctx->cfg.local_time = 0; 264 ctx->cfg.local_time = 0;
265 ctx->cfg.enable_tree_linenumbers = 1;
263 ctx->cfg.max_repo_count = 50; 266 ctx->cfg.max_repo_count = 50;
264 ctx->cfg.max_commit_count = 50; 267 ctx->cfg.max_commit_count = 50;
265 ctx->cfg.max_lock_attempts = 5; 268 ctx->cfg.max_lock_attempts = 5;
266 ctx->cfg.max_msg_len = 80; 269 ctx->cfg.max_msg_len = 80;
267 ctx->cfg.max_repodesc_len = 80; 270 ctx->cfg.max_repodesc_len = 80;
268 ctx->cfg.max_stats = 0; 271 ctx->cfg.max_stats = 0;
269 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 272 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
270 ctx->cfg.renamelimit = -1; 273 ctx->cfg.renamelimit = -1;
271 ctx->cfg.robots = "index, nofollow"; 274 ctx->cfg.robots = "index, nofollow";
272 ctx->cfg.root_title = "Git repository browser"; 275 ctx->cfg.root_title = "Git repository browser";
273 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 276 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
274 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 277 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
275 ctx->cfg.section = ""; 278 ctx->cfg.section = "";
276 ctx->cfg.summary_branches = 10; 279 ctx->cfg.summary_branches = 10;
277 ctx->cfg.summary_log = 10; 280 ctx->cfg.summary_log = 10;
278 ctx->cfg.summary_tags = 10; 281 ctx->cfg.summary_tags = 10;
279 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); 282 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));
280 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); 283 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST"));
281 ctx->env.https = xstrdupn(getenv("HTTPS")); 284 ctx->env.https = xstrdupn(getenv("HTTPS"));
282 ctx->env.no_http = xstrdupn(getenv("NO_HTTP")); 285 ctx->env.no_http = xstrdupn(getenv("NO_HTTP"));
283 ctx->env.path_info = xstrdupn(getenv("PATH_INFO")); 286 ctx->env.path_info = xstrdupn(getenv("PATH_INFO"));
284 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING")); 287 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING"));
285 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD")); 288 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD"));
286 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME")); 289 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
287 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME")); 290 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME"));
288 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT")); 291 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT"));
289 ctx->page.mimetype = "text/html"; 292 ctx->page.mimetype = "text/html";
290 ctx->page.charset = PAGE_ENCODING; 293 ctx->page.charset = PAGE_ENCODING;
291 ctx->page.filename = NULL; 294 ctx->page.filename = NULL;
292 ctx->page.size = 0; 295 ctx->page.size = 0;
293 ctx->page.modified = time(NULL); 296 ctx->page.modified = time(NULL);
294 ctx->page.expires = ctx->page.modified; 297 ctx->page.expires = ctx->page.modified;
295 ctx->page.etag = NULL; 298 ctx->page.etag = NULL;
296 memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list)); 299 memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list));
297 if (ctx->env.script_name) 300 if (ctx->env.script_name)
298 ctx->cfg.script_name = ctx->env.script_name; 301 ctx->cfg.script_name = ctx->env.script_name;
299 if (ctx->env.query_string) 302 if (ctx->env.query_string)
300 ctx->qry.raw = ctx->env.query_string; 303 ctx->qry.raw = ctx->env.query_string;
301 if (!ctx->env.cgit_config) 304 if (!ctx->env.cgit_config)
302 ctx->env.cgit_config = CGIT_CONFIG; 305 ctx->env.cgit_config = CGIT_CONFIG;
303} 306}
304 307
305struct refmatch { 308struct refmatch {
306 char *req_ref; 309 char *req_ref;
307 char *first_ref; 310 char *first_ref;
308 int match; 311 int match;
309}; 312};
310 313
diff --git a/cgit.css b/cgit.css
index 3c65114..c47ebc9 100644
--- a/cgit.css
+++ b/cgit.css
@@ -192,106 +192,106 @@ td#content {
192div#summary { 192div#summary {
193 vertical-align: top; 193 vertical-align: top;
194 margin-bottom: 1em; 194 margin-bottom: 1em;
195} 195}
196 196
197table#downloads { 197table#downloads {
198 float: right; 198 float: right;
199 border-collapse: collapse; 199 border-collapse: collapse;
200 border: solid 1px #777; 200 border: solid 1px #777;
201 margin-left: 0.5em; 201 margin-left: 0.5em;
202 margin-bottom: 0.5em; 202 margin-bottom: 0.5em;
203} 203}
204 204
205table#downloads th { 205table#downloads th {
206 background-color: #ccc; 206 background-color: #ccc;
207} 207}
208 208
209div#blob { 209div#blob {
210 border: solid 1px black; 210 border: solid 1px black;
211} 211}
212 212
213div.error { 213div.error {
214 color: red; 214 color: red;
215 font-weight: bold; 215 font-weight: bold;
216 margin: 1em 2em; 216 margin: 1em 2em;
217} 217}
218 218
219a.ls-blob, a.ls-dir, a.ls-mod { 219a.ls-blob, a.ls-dir, a.ls-mod {
220 font-family: monospace; 220 font-family: monospace;
221} 221}
222 222
223td.ls-size { 223td.ls-size {
224 text-align: right; 224 text-align: right;
225 font-family: monospace; 225 font-family: monospace;
226 width: 10em; 226 width: 10em;
227} 227}
228 228
229td.ls-mode { 229td.ls-mode {
230 font-family: monospace; 230 font-family: monospace;
231 width: 10em; 231 width: 10em;
232} 232}
233 233
234table.blob { 234table.blob {
235 margin-top: 0.5em; 235 margin-top: 0.5em;
236 border-top: solid 1px black; 236 border-top: solid 1px black;
237} 237}
238 238
239table.blob td.lines { 239table.blob td.lines {
240 margin: 0; padding: 0; 240 margin: 0; padding: 0 0 0 0.5em;
241 vertical-align: top; 241 vertical-align: top;
242 color: black; 242 color: black;
243} 243}
244 244
245table.blob td.linenumbers { 245table.blob td.linenumbers {
246 margin: 0; padding: 0; 246 margin: 0; padding: 0 0.5em 0 0.5em;
247 vertical-align: top; 247 vertical-align: top;
248 text-align: right;
248 border-right: 1px solid gray; 249 border-right: 1px solid gray;
249 background-color: #eee;
250} 250}
251 251
252table.blob pre { 252table.blob pre {
253 padding: 0; margin: 0; 253 padding: 0; margin: 0;
254} 254}
255 255
256table.blob a.no { 256table.blob a.no {
257 color: gray; 257 color: gray;
258 text-align: right; 258 text-align: right;
259 text-decoration: none; 259 text-decoration: none;
260} 260}
261 261
262table.blob a.no a:hover { 262table.blob a.no a:hover {
263 color: black; 263 color: black;
264} 264}
265 265
266table.bin-blob { 266table.bin-blob {
267 margin-top: 0.5em; 267 margin-top: 0.5em;
268 border: solid 1px black; 268 border: solid 1px black;
269} 269}
270 270
271table.bin-blob th { 271table.bin-blob th {
272 font-family: monospace; 272 font-family: monospace;
273 white-space: pre; 273 white-space: pre;
274 border: solid 1px #777; 274 border: solid 1px #777;
275 padding: 0.5em 1em; 275 padding: 0.5em 1em;
276} 276}
277 277
278table.bin-blob td { 278table.bin-blob td {
279 font-family: monospace; 279 font-family: monospace;
280 white-space: pre; 280 white-space: pre;
281 border-left: solid 1px #777; 281 border-left: solid 1px #777;
282 padding: 0em 1em; 282 padding: 0em 1em;
283} 283}
284 284
285table.nowrap td { 285table.nowrap td {
286 white-space: nowrap; 286 white-space: nowrap;
287} 287}
288 288
289table.commit-info { 289table.commit-info {
290 border-collapse: collapse; 290 border-collapse: collapse;
291 margin-top: 1.5em; 291 margin-top: 1.5em;
292} 292}
293 293
294table.commit-info th { 294table.commit-info th {
295 text-align: left; 295 text-align: left;
296 font-weight: normal; 296 font-weight: normal;
297 padding: 0.1em 1em 0.1em 0.1em; 297 padding: 0.1em 1em 0.1em 0.1em;
diff --git a/cgit.h b/cgit.h
index ef109aa..6c6c460 100644
--- a/cgit.h
+++ b/cgit.h
@@ -133,96 +133,97 @@ struct cgit_query {
133 char *grep; 133 char *grep;
134 char *head; 134 char *head;
135 char *sha1; 135 char *sha1;
136 char *sha2; 136 char *sha2;
137 char *path; 137 char *path;
138 char *name; 138 char *name;
139 char *mimetype; 139 char *mimetype;
140 char *url; 140 char *url;
141 char *period; 141 char *period;
142 int ofs; 142 int ofs;
143 int nohead; 143 int nohead;
144 char *sort; 144 char *sort;
145 int showmsg; 145 int showmsg;
146}; 146};
147 147
148struct cgit_config { 148struct cgit_config {
149 char *agefile; 149 char *agefile;
150 char *cache_root; 150 char *cache_root;
151 char *clone_prefix; 151 char *clone_prefix;
152 char *css; 152 char *css;
153 char *favicon; 153 char *favicon;
154 char *footer; 154 char *footer;
155 char *head_include; 155 char *head_include;
156 char *header; 156 char *header;
157 char *index_header; 157 char *index_header;
158 char *index_info; 158 char *index_info;
159 char *logo; 159 char *logo;
160 char *logo_link; 160 char *logo_link;
161 char *module_link; 161 char *module_link;
162 char *robots; 162 char *robots;
163 char *root_title; 163 char *root_title;
164 char *root_desc; 164 char *root_desc;
165 char *root_readme; 165 char *root_readme;
166 char *script_name; 166 char *script_name;
167 char *section; 167 char *section;
168 char *virtual_root; 168 char *virtual_root;
169 int cache_size; 169 int cache_size;
170 int cache_dynamic_ttl; 170 int cache_dynamic_ttl;
171 int cache_max_create_time; 171 int cache_max_create_time;
172 int cache_repo_ttl; 172 int cache_repo_ttl;
173 int cache_root_ttl; 173 int cache_root_ttl;
174 int cache_scanrc_ttl; 174 int cache_scanrc_ttl;
175 int cache_static_ttl; 175 int cache_static_ttl;
176 int embedded; 176 int embedded;
177 int enable_filter_overrides; 177 int enable_filter_overrides;
178 int enable_index_links; 178 int enable_index_links;
179 int enable_log_filecount; 179 int enable_log_filecount;
180 int enable_log_linecount; 180 int enable_log_linecount;
181 int enable_tree_linenumbers;
181 int local_time; 182 int local_time;
182 int max_repo_count; 183 int max_repo_count;
183 int max_commit_count; 184 int max_commit_count;
184 int max_lock_attempts; 185 int max_lock_attempts;
185 int max_msg_len; 186 int max_msg_len;
186 int max_repodesc_len; 187 int max_repodesc_len;
187 int max_stats; 188 int max_stats;
188 int nocache; 189 int nocache;
189 int noplainemail; 190 int noplainemail;
190 int noheader; 191 int noheader;
191 int renamelimit; 192 int renamelimit;
192 int snapshots; 193 int snapshots;
193 int summary_branches; 194 int summary_branches;
194 int summary_log; 195 int summary_log;
195 int summary_tags; 196 int summary_tags;
196 struct string_list mimetypes; 197 struct string_list mimetypes;
197 struct cgit_filter *about_filter; 198 struct cgit_filter *about_filter;
198 struct cgit_filter *commit_filter; 199 struct cgit_filter *commit_filter;
199 struct cgit_filter *source_filter; 200 struct cgit_filter *source_filter;
200}; 201};
201 202
202struct cgit_page { 203struct cgit_page {
203 time_t modified; 204 time_t modified;
204 time_t expires; 205 time_t expires;
205 size_t size; 206 size_t size;
206 char *mimetype; 207 char *mimetype;
207 char *charset; 208 char *charset;
208 char *filename; 209 char *filename;
209 char *etag; 210 char *etag;
210 char *title; 211 char *title;
211 int status; 212 int status;
212 char *statusmsg; 213 char *statusmsg;
213}; 214};
214 215
215struct cgit_environment { 216struct cgit_environment {
216 char *cgit_config; 217 char *cgit_config;
217 char *http_host; 218 char *http_host;
218 char *https; 219 char *https;
219 char *no_http; 220 char *no_http;
220 char *path_info; 221 char *path_info;
221 char *query_string; 222 char *query_string;
222 char *request_method; 223 char *request_method;
223 char *script_name; 224 char *script_name;
224 char *server_name; 225 char *server_name;
225 char *server_port; 226 char *server_port;
226}; 227};
227 228
228struct cgit_context { 229struct cgit_context {
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 617b7c3..4dc383d 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -62,96 +62,100 @@ cache-size::
62 The maximum number of entries in the cgit cache. Default value: "0" 62 The maximum number of entries in the cgit cache. Default value: "0"
63 (i.e. caching is disabled). 63 (i.e. caching is disabled).
64 64
65cache-static-ttl:: 65cache-static-ttl::
66 Number which specifies the time-to-live, in minutes, for the cached 66 Number which specifies the time-to-live, in minutes, for the cached
67 version of repository pages accessed with a fixed SHA1. Default value: 67 version of repository pages accessed with a fixed SHA1. Default value:
68 "5". 68 "5".
69 69
70clone-prefix:: 70clone-prefix::
71 Space-separated list of common prefixes which, when combined with a 71 Space-separated list of common prefixes which, when combined with a
72 repository url, generates valid clone urls for the repository. This 72 repository url, generates valid clone urls for the repository. This
73 setting is only used if `repo.clone-url` is unspecified. Default value: 73 setting is only used if `repo.clone-url` is unspecified. Default value:
74 none. 74 none.
75 75
76commit-filter:: 76commit-filter::
77 Specifies a command which will be invoked to format commit messages. 77 Specifies a command which will be invoked to format commit messages.
78 The command will get the message on its STDIN, and the STDOUT from the 78 The command will get the message on its STDIN, and the STDOUT from the
79 command will be included verbatim as the commit message, i.e. this can 79 command will be included verbatim as the commit message, i.e. this can
80 be used to implement bugtracker integration. Default value: none. 80 be used to implement bugtracker integration. Default value: none.
81 81
82css:: 82css::
83 Url which specifies the css document to include in all cgit pages. 83 Url which specifies the css document to include in all cgit pages.
84 Default value: "/cgit.css". 84 Default value: "/cgit.css".
85 85
86embedded:: 86embedded::
87 Flag which, when set to "1", will make cgit generate a html fragment 87 Flag which, when set to "1", will make cgit generate a html fragment
88 suitable for embedding in other html pages. Default value: none. See 88 suitable for embedding in other html pages. Default value: none. See
89 also: "noheader". 89 also: "noheader".
90 90
91enable-filter-overrides:: 91enable-filter-overrides::
92 Flag which, when set to "1", allows all filter settings to be 92 Flag which, when set to "1", allows all filter settings to be
93 overridden in repository-specific cgitrc files. Default value: none. 93 overridden in repository-specific cgitrc files. Default value: none.
94 94
95enable-index-links:: 95enable-index-links::
96 Flag which, when set to "1", will make cgit generate extra links for 96 Flag which, when set to "1", will make cgit generate extra links for
97 each repo in the repository index (specifically, to the "summary", 97 each repo in the repository index (specifically, to the "summary",
98 "commit" and "tree" pages). Default value: "0". 98 "commit" and "tree" pages). Default value: "0".
99 99
100enable-log-filecount:: 100enable-log-filecount::
101 Flag which, when set to "1", will make cgit print the number of 101 Flag which, when set to "1", will make cgit print the number of
102 modified files for each commit on the repository log page. Default 102 modified files for each commit on the repository log page. Default
103 value: "0". 103 value: "0".
104 104
105enable-log-linecount:: 105enable-log-linecount::
106 Flag which, when set to "1", will make cgit print the number of added 106 Flag which, when set to "1", will make cgit print the number of added
107 and removed lines for each commit on the repository log page. Default 107 and removed lines for each commit on the repository log page. Default
108 value: "0". 108 value: "0".
109 109
110enable-tree-linenumbers::
111 Flag which, when set to "1", will make cgit generate linenumber links
112 for plaintext blobs printed in the tree view. Default value: "1".
113
110favicon:: 114favicon::
111 Url used as link to a shortcut icon for cgit. If specified, it is 115 Url used as link to a shortcut icon for cgit. If specified, it is
112 suggested to use the value "/favicon.ico" since certain browsers will 116 suggested to use the value "/favicon.ico" since certain browsers will
113 ignore other values. Default value: none. 117 ignore other values. Default value: none.
114 118
115footer:: 119footer::
116 The content of the file specified with this option will be included 120 The content of the file specified with this option will be included
117 verbatim at the bottom of all pages (i.e. it replaces the standard 121 verbatim at the bottom of all pages (i.e. it replaces the standard
118 "generated by..." message. Default value: none. 122 "generated by..." message. Default value: none.
119 123
120head-include:: 124head-include::
121 The content of the file specified with this option will be included 125 The content of the file specified with this option will be included
122 verbatim in the html HEAD section on all pages. Default value: none. 126 verbatim in the html HEAD section on all pages. Default value: none.
123 127
124header:: 128header::
125 The content of the file specified with this option will be included 129 The content of the file specified with this option will be included
126 verbatim at the top of all pages. Default value: none. 130 verbatim at the top of all pages. Default value: none.
127 131
128include:: 132include::
129 Name of a configfile to include before the rest of the current config- 133 Name of a configfile to include before the rest of the current config-
130 file is parsed. Default value: none. 134 file is parsed. Default value: none.
131 135
132index-header:: 136index-header::
133 The content of the file specified with this option will be included 137 The content of the file specified with this option will be included
134 verbatim above the repository index. This setting is deprecated, and 138 verbatim above the repository index. This setting is deprecated, and
135 will not be supported by cgit-1.0 (use root-readme instead). Default 139 will not be supported by cgit-1.0 (use root-readme instead). Default
136 value: none. 140 value: none.
137 141
138index-info:: 142index-info::
139 The content of the file specified with this option will be included 143 The content of the file specified with this option will be included
140 verbatim below the heading on the repository index page. This setting 144 verbatim below the heading on the repository index page. This setting
141 is deprecated, and will not be supported by cgit-1.0 (use root-desc 145 is deprecated, and will not be supported by cgit-1.0 (use root-desc
142 instead). Default value: none. 146 instead). Default value: none.
143 147
144local-time:: 148local-time::
145 Flag which, if set to "1", makes cgit print commit and tag times in the 149 Flag which, if set to "1", makes cgit print commit and tag times in the
146 servers timezone. Default value: "0". 150 servers timezone. Default value: "0".
147 151
148logo:: 152logo::
149 Url which specifies the source of an image which will be used as a logo 153 Url which specifies the source of an image which will be used as a logo
150 on all cgit pages. Default value: "/cgit.png". 154 on all cgit pages. Default value: "/cgit.png".
151 155
152logo-link:: 156logo-link::
153 Url loaded when clicking on the cgit logo image. If unspecified the 157 Url loaded when clicking on the cgit logo image. If unspecified the
154 calculated url of the repository index page will be used. Default 158 calculated url of the repository index page will be used. Default
155 value: none. 159 value: none.
156 160
157max-commit-count:: 161max-commit-count::
diff --git a/git b/git
Subproject e276f018f2c1f0fc962fbe44a36708d1cdebada Subproject 7fb6bcff2dece2ff9fbc5ebfe526d9b2a7e764c
diff --git a/ui-commit.c b/ui-commit.c
index d6b73ee..f5b0ae5 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -1,86 +1,86 @@
1/* ui-commit.c: generate commit view 1/* ui-commit.c: generate commit view
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 "html.h" 10#include "html.h"
11#include "ui-shared.h" 11#include "ui-shared.h"
12#include "ui-diff.h" 12#include "ui-diff.h"
13#include "ui-log.h" 13#include "ui-log.h"
14 14
15void cgit_print_commit(char *hex) 15void cgit_print_commit(char *hex)
16{ 16{
17 struct commit *commit, *parent; 17 struct commit *commit, *parent;
18 struct commitinfo *info; 18 struct commitinfo *info;
19 struct commit_list *p; 19 struct commit_list *p;
20 unsigned char sha1[20]; 20 unsigned char sha1[20];
21 char *tmp; 21 char *tmp;
22 int parents = 0; 22 int parents = 0;
23 23
24 if (!hex) 24 if (!hex)
25 hex = ctx.qry.head; 25 hex = ctx.qry.head;
26 26
27 if (get_sha1(hex, sha1)) { 27 if (get_sha1(hex, sha1)) {
28 cgit_print_error(fmt("Bad object id: %s", hex)); 28 cgit_print_error(fmt("Bad object id: %s", hex));
29 return; 29 return;
30 } 30 }
31 commit = lookup_commit_reference(sha1); 31 commit = lookup_commit_reference(sha1);
32 if (!commit) { 32 if (!commit) {
33 cgit_print_error(fmt("Bad commit reference: %s", hex)); 33 cgit_print_error(fmt("Bad commit reference: %s", hex));
34 return; 34 return;
35 } 35 }
36 info = cgit_parse_commit(commit); 36 info = cgit_parse_commit(commit);
37 37
38 load_ref_decorations(); 38 load_ref_decorations(DECORATE_FULL_REFS);
39 39
40 html("<table summary='commit info' class='commit-info'>\n"); 40 html("<table summary='commit info' class='commit-info'>\n");
41 html("<tr><th>author</th><td>"); 41 html("<tr><th>author</th><td>");
42 html_txt(info->author); 42 html_txt(info->author);
43 if (!ctx.cfg.noplainemail) { 43 if (!ctx.cfg.noplainemail) {
44 html(" "); 44 html(" ");
45 html_txt(info->author_email); 45 html_txt(info->author_email);
46 } 46 }
47 html("</td><td class='right'>"); 47 html("</td><td class='right'>");
48 cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time); 48 cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time);
49 html("</td></tr>\n"); 49 html("</td></tr>\n");
50 html("<tr><th>committer</th><td>"); 50 html("<tr><th>committer</th><td>");
51 html_txt(info->committer); 51 html_txt(info->committer);
52 if (!ctx.cfg.noplainemail) { 52 if (!ctx.cfg.noplainemail) {
53 html(" "); 53 html(" ");
54 html_txt(info->committer_email); 54 html_txt(info->committer_email);
55 } 55 }
56 html("</td><td class='right'>"); 56 html("</td><td class='right'>");
57 cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time); 57 cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time);
58 html("</td></tr>\n"); 58 html("</td></tr>\n");
59 html("<tr><th>commit</th><td colspan='2' class='sha1'>"); 59 html("<tr><th>commit</th><td colspan='2' class='sha1'>");
60 tmp = sha1_to_hex(commit->object.sha1); 60 tmp = sha1_to_hex(commit->object.sha1);
61 cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp); 61 cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp);
62 html(" ("); 62 html(" (");
63 cgit_patch_link("patch", NULL, NULL, NULL, tmp); 63 cgit_patch_link("patch", NULL, NULL, NULL, tmp);
64 html(")</td></tr>\n"); 64 html(")</td></tr>\n");
65 html("<tr><th>tree</th><td colspan='2' class='sha1'>"); 65 html("<tr><th>tree</th><td colspan='2' class='sha1'>");
66 tmp = xstrdup(hex); 66 tmp = xstrdup(hex);
67 cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL, 67 cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL,
68 ctx.qry.head, tmp, NULL); 68 ctx.qry.head, tmp, NULL);
69 html("</td></tr>\n"); 69 html("</td></tr>\n");
70 for (p = commit->parents; p ; p = p->next) { 70 for (p = commit->parents; p ; p = p->next) {
71 parent = lookup_commit_reference(p->item->object.sha1); 71 parent = lookup_commit_reference(p->item->object.sha1);
72 if (!parent) { 72 if (!parent) {
73 html("<tr><td colspan='3'>"); 73 html("<tr><td colspan='3'>");
74 cgit_print_error("Error reading parent commit"); 74 cgit_print_error("Error reading parent commit");
75 html("</td></tr>"); 75 html("</td></tr>");
76 continue; 76 continue;
77 } 77 }
78 html("<tr><th>parent</th>" 78 html("<tr><th>parent</th>"
79 "<td colspan='2' class='sha1'>"); 79 "<td colspan='2' class='sha1'>");
80 cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, 80 cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL,
81 ctx.qry.head, sha1_to_hex(p->item->object.sha1)); 81 ctx.qry.head, sha1_to_hex(p->item->object.sha1));
82 html(" ("); 82 html(" (");
83 cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, 83 cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex,
84 sha1_to_hex(p->item->object.sha1), NULL); 84 sha1_to_hex(p->item->object.sha1), NULL);
85 html(")</td></tr>"); 85 html(")</td></tr>");
86 parents++; 86 parents++;
diff --git a/ui-log.c b/ui-log.c
index 0b37785..f3132c9 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -116,97 +116,97 @@ void print_commit(struct commit *commit)
116 cols); 116 cols);
117 html_txt(info->msg); 117 html_txt(info->msg);
118 html("</td></tr>\n"); 118 html("</td></tr>\n");
119 } 119 }
120 cgit_free_commitinfo(info); 120 cgit_free_commitinfo(info);
121} 121}
122 122
123static const char *disambiguate_ref(const char *ref) 123static const char *disambiguate_ref(const char *ref)
124{ 124{
125 unsigned char sha1[20]; 125 unsigned char sha1[20];
126 const char *longref; 126 const char *longref;
127 127
128 longref = fmt("refs/heads/%s", ref); 128 longref = fmt("refs/heads/%s", ref);
129 if (get_sha1(longref, sha1) == 0) 129 if (get_sha1(longref, sha1) == 0)
130 return longref; 130 return longref;
131 131
132 return ref; 132 return ref;
133} 133}
134 134
135void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern, 135void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern,
136 char *path, int pager) 136 char *path, int pager)
137{ 137{
138 struct rev_info rev; 138 struct rev_info rev;
139 struct commit *commit; 139 struct commit *commit;
140 const char *argv[] = {NULL, NULL, NULL, NULL, NULL}; 140 const char *argv[] = {NULL, NULL, NULL, NULL, NULL};
141 int argc = 2; 141 int argc = 2;
142 int i, columns = 3; 142 int i, columns = 3;
143 143
144 if (!tip) 144 if (!tip)
145 tip = ctx.qry.head; 145 tip = ctx.qry.head;
146 146
147 argv[1] = disambiguate_ref(tip); 147 argv[1] = disambiguate_ref(tip);
148 148
149 if (grep && pattern && (!strcmp(grep, "grep") || 149 if (grep && pattern && (!strcmp(grep, "grep") ||
150 !strcmp(grep, "author") || 150 !strcmp(grep, "author") ||
151 !strcmp(grep, "committer"))) 151 !strcmp(grep, "committer")))
152 argv[argc++] = fmt("--%s=%s", grep, pattern); 152 argv[argc++] = fmt("--%s=%s", grep, pattern);
153 153
154 if (path) { 154 if (path) {
155 argv[argc++] = "--"; 155 argv[argc++] = "--";
156 argv[argc++] = path; 156 argv[argc++] = path;
157 } 157 }
158 init_revisions(&rev, NULL); 158 init_revisions(&rev, NULL);
159 rev.abbrev = DEFAULT_ABBREV; 159 rev.abbrev = DEFAULT_ABBREV;
160 rev.commit_format = CMIT_FMT_DEFAULT; 160 rev.commit_format = CMIT_FMT_DEFAULT;
161 rev.verbose_header = 1; 161 rev.verbose_header = 1;
162 rev.show_root_diff = 0; 162 rev.show_root_diff = 0;
163 setup_revisions(argc, argv, &rev, NULL); 163 setup_revisions(argc, argv, &rev, NULL);
164 load_ref_decorations(); 164 load_ref_decorations(DECORATE_FULL_REFS);
165 rev.show_decorations = 1; 165 rev.show_decorations = 1;
166 rev.grep_filter.regflags |= REG_ICASE; 166 rev.grep_filter.regflags |= REG_ICASE;
167 compile_grep_patterns(&rev.grep_filter); 167 compile_grep_patterns(&rev.grep_filter);
168 prepare_revision_walk(&rev); 168 prepare_revision_walk(&rev);
169 169
170 if (pager) 170 if (pager)
171 html("<table class='list nowrap'>"); 171 html("<table class='list nowrap'>");
172 172
173 html("<tr class='nohover'><th class='left'>Age</th>" 173 html("<tr class='nohover'><th class='left'>Age</th>"
174 "<th class='left'>Commit message"); 174 "<th class='left'>Commit message");
175 if (pager) { 175 if (pager) {
176 html(" ("); 176 html(" (");
177 cgit_log_link(ctx.qry.showmsg ? "Collapse" : "Expand", NULL, 177 cgit_log_link(ctx.qry.showmsg ? "Collapse" : "Expand", NULL,
178 NULL, ctx.qry.head, ctx.qry.sha1, 178 NULL, ctx.qry.head, ctx.qry.sha1,
179 ctx.qry.path, ctx.qry.ofs, ctx.qry.grep, 179 ctx.qry.path, ctx.qry.ofs, ctx.qry.grep,
180 ctx.qry.search, ctx.qry.showmsg ? 0 : 1); 180 ctx.qry.search, ctx.qry.showmsg ? 0 : 1);
181 html(")"); 181 html(")");
182 } 182 }
183 html("</th><th class='left'>Author</th>"); 183 html("</th><th class='left'>Author</th>");
184 if (ctx.repo->enable_log_filecount) { 184 if (ctx.repo->enable_log_filecount) {
185 html("<th class='left'>Files</th>"); 185 html("<th class='left'>Files</th>");
186 columns++; 186 columns++;
187 if (ctx.repo->enable_log_linecount) { 187 if (ctx.repo->enable_log_linecount) {
188 html("<th class='left'>Lines</th>"); 188 html("<th class='left'>Lines</th>");
189 columns++; 189 columns++;
190 } 190 }
191 } 191 }
192 html("</tr>\n"); 192 html("</tr>\n");
193 193
194 if (ofs<0) 194 if (ofs<0)
195 ofs = 0; 195 ofs = 0;
196 196
197 for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) { 197 for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) {
198 free(commit->buffer); 198 free(commit->buffer);
199 commit->buffer = NULL; 199 commit->buffer = NULL;
200 free_commit_list(commit->parents); 200 free_commit_list(commit->parents);
201 commit->parents = NULL; 201 commit->parents = NULL;
202 } 202 }
203 203
204 for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) { 204 for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) {
205 print_commit(commit); 205 print_commit(commit);
206 free(commit->buffer); 206 free(commit->buffer);
207 commit->buffer = NULL; 207 commit->buffer = NULL;
208 free_commit_list(commit->parents); 208 free_commit_list(commit->parents);
209 commit->parents = NULL; 209 commit->parents = NULL;
210 } 210 }
211 if (pager) { 211 if (pager) {
212 htmlf("</table><div class='pager'>", 212 htmlf("</table><div class='pager'>",
diff --git a/ui-plain.c b/ui-plain.c
index 27c6dae..a4ce077 100644
--- a/ui-plain.c
+++ b/ui-plain.c
@@ -15,79 +15,80 @@ char *match_path;
15int match; 15int match;
16 16
17static void print_object(const unsigned char *sha1, const char *path) 17static void print_object(const unsigned char *sha1, const char *path)
18{ 18{
19 enum object_type type; 19 enum object_type type;
20 char *buf, *ext; 20 char *buf, *ext;
21 unsigned long size; 21 unsigned long size;
22 struct string_list_item *mime; 22 struct string_list_item *mime;
23 23
24 type = sha1_object_info(sha1, &size); 24 type = sha1_object_info(sha1, &size);
25 if (type == OBJ_BAD) { 25 if (type == OBJ_BAD) {
26 html_status(404, "Not found", 0); 26 html_status(404, "Not found", 0);
27 return; 27 return;
28 } 28 }
29 29
30 buf = read_sha1_file(sha1, &type, &size); 30 buf = read_sha1_file(sha1, &type, &size);
31 if (!buf) { 31 if (!buf) {
32 html_status(404, "Not found", 0); 32 html_status(404, "Not found", 0);
33 return; 33 return;
34 } 34 }
35 ctx.page.mimetype = NULL; 35 ctx.page.mimetype = NULL;
36 ext = strrchr(path, '.'); 36 ext = strrchr(path, '.');
37 if (ext && *(++ext)) { 37 if (ext && *(++ext)) {
38 mime = string_list_lookup(ext, &ctx.cfg.mimetypes); 38 mime = string_list_lookup(ext, &ctx.cfg.mimetypes);
39 if (mime) 39 if (mime)
40 ctx.page.mimetype = (char *)mime->util; 40 ctx.page.mimetype = (char *)mime->util;
41 } 41 }
42 if (!ctx.page.mimetype) { 42 if (!ctx.page.mimetype) {
43 if (buffer_is_binary(buf, size)) 43 if (buffer_is_binary(buf, size))
44 ctx.page.mimetype = "application/octet-stream"; 44 ctx.page.mimetype = "application/octet-stream";
45 else 45 else
46 ctx.page.mimetype = "text/plain"; 46 ctx.page.mimetype = "text/plain";
47 } 47 }
48 ctx.page.filename = fmt("%s", path); 48 ctx.page.filename = fmt("%s", path);
49 ctx.page.size = size; 49 ctx.page.size = size;
50 ctx.page.etag = sha1_to_hex(sha1); 50 ctx.page.etag = sha1_to_hex(sha1);
51 cgit_print_http_headers(&ctx); 51 cgit_print_http_headers(&ctx);
52 html_raw(buf, size); 52 html_raw(buf, size);
53 match = 1; 53 match = 1;
54} 54}
55 55
56static int walk_tree(const unsigned char *sha1, const char *base, int baselen, 56static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
57 const char *pathname, unsigned mode, int stage, 57 const char *pathname, unsigned mode, int stage,
58 void *cbdata) 58 void *cbdata)
59{ 59{
60 if (S_ISDIR(mode)) 60 if (S_ISDIR(mode))
61 return READ_TREE_RECURSIVE; 61 return READ_TREE_RECURSIVE;
62 62
63 if (S_ISREG(mode)) 63 if (S_ISREG(mode) && !strncmp(base, match_path, baselen) &&
64 !strcmp(pathname, match_path + baselen))
64 print_object(sha1, pathname); 65 print_object(sha1, pathname);
65 66
66 return 0; 67 return 0;
67} 68}
68 69
69void cgit_print_plain(struct cgit_context *ctx) 70void cgit_print_plain(struct cgit_context *ctx)
70{ 71{
71 const char *rev = ctx->qry.sha1; 72 const char *rev = ctx->qry.sha1;
72 unsigned char sha1[20]; 73 unsigned char sha1[20];
73 struct commit *commit; 74 struct commit *commit;
74 const char *paths[] = {ctx->qry.path, NULL}; 75 const char *paths[] = {ctx->qry.path, NULL};
75 76
76 if (!rev) 77 if (!rev)
77 rev = ctx->qry.head; 78 rev = ctx->qry.head;
78 79
79 curr_rev = xstrdup(rev); 80 curr_rev = xstrdup(rev);
80 if (get_sha1(rev, sha1)) { 81 if (get_sha1(rev, sha1)) {
81 html_status(404, "Not found", 0); 82 html_status(404, "Not found", 0);
82 return; 83 return;
83 } 84 }
84 commit = lookup_commit_reference(sha1); 85 commit = lookup_commit_reference(sha1);
85 if (!commit || parse_commit(commit)) { 86 if (!commit || parse_commit(commit)) {
86 html_status(404, "Not found", 0); 87 html_status(404, "Not found", 0);
87 return; 88 return;
88 } 89 }
89 match_path = ctx->qry.path; 90 match_path = ctx->qry.path;
90 read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL); 91 read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL);
91 if (!match) 92 if (!match)
92 html_status(404, "Not found", 0); 93 html_status(404, "Not found", 0);
93} 94}
diff --git a/ui-tree.c b/ui-tree.c
index c608754..f53ab64 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -1,95 +1,102 @@
1/* ui-tree.c: functions for tree output 1/* ui-tree.c: functions for tree output
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 <ctype.h> 9#include <ctype.h>
10#include "cgit.h" 10#include "cgit.h"
11#include "html.h" 11#include "html.h"
12#include "ui-shared.h" 12#include "ui-shared.h"
13 13
14char *curr_rev; 14char *curr_rev;
15char *match_path; 15char *match_path;
16int header = 0; 16int header = 0;
17 17
18static void print_text_buffer(const char *name, char *buf, unsigned long size) 18static void print_text_buffer(const char *name, char *buf, unsigned long size)
19{ 19{
20 unsigned long lineno, idx; 20 unsigned long lineno, idx;
21 const char *numberfmt = 21 const char *numberfmt =
22 "<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n"; 22 "<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n";
23 23
24 html("<table summary='blob content' class='blob'>\n"); 24 html("<table summary='blob content' class='blob'>\n");
25
26 if (ctx.cfg.enable_tree_linenumbers) {
27 html("<tr><td class='linenumbers'><pre>");
28 idx = 0;
29 lineno = 0;
30
31 if (size) {
32 htmlf(numberfmt, ++lineno);
33 while(idx < size - 1) { // skip absolute last newline
34 if (buf[idx] == '\n')
35 htmlf(numberfmt, ++lineno);
36 idx++;
37 }
38 }
39 html("</pre></td>\n");
40 }
41 else {
42 html("<tr>\n");
43 }
44
25 if (ctx.repo->source_filter) { 45 if (ctx.repo->source_filter) {
26 html("<tr><td class='lines'><pre><code>"); 46 html("<td class='lines'><pre><code>");
27 ctx.repo->source_filter->argv[1] = xstrdup(name); 47 ctx.repo->source_filter->argv[1] = xstrdup(name);
28 cgit_open_filter(ctx.repo->source_filter); 48 cgit_open_filter(ctx.repo->source_filter);
29 write(STDOUT_FILENO, buf, size); 49 write(STDOUT_FILENO, buf, size);
30 cgit_close_filter(ctx.repo->source_filter); 50 cgit_close_filter(ctx.repo->source_filter);
31 html("</code></pre></td></tr></table>\n"); 51 html("</code></pre></td></tr></table>\n");
32 return; 52 return;
33 } 53 }
34 54
35 html("<tr><td class='linenumbers'><pre>");
36 idx = 0;
37 lineno = 0;
38
39 if (size) {
40 htmlf(numberfmt, ++lineno);
41 while(idx < size - 1) { // skip absolute last newline
42 if (buf[idx] == '\n')
43 htmlf(numberfmt, ++lineno);
44 idx++;
45 }
46 }
47 html("</pre></td>\n");
48 html("<td class='lines'><pre><code>"); 55 html("<td class='lines'><pre><code>");
49 html_txt(buf); 56 html_txt(buf);
50 html("</code></pre></td></tr></table>\n"); 57 html("</code></pre></td></tr></table>\n");
51} 58}
52 59
53#define ROWLEN 32 60#define ROWLEN 32
54 61
55static void print_binary_buffer(char *buf, unsigned long size) 62static void print_binary_buffer(char *buf, unsigned long size)
56{ 63{
57 unsigned long ofs, idx; 64 unsigned long ofs, idx;
58 static char ascii[ROWLEN + 1]; 65 static char ascii[ROWLEN + 1];
59 66
60 html("<table summary='blob content' class='bin-blob'>\n"); 67 html("<table summary='blob content' class='bin-blob'>\n");
61 html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>"); 68 html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>");
62 for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) { 69 for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) {
63 htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs); 70 htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs);
64 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) 71 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
65 htmlf("%*s%02x", 72 htmlf("%*s%02x",
66 idx == 16 ? 4 : 1, "", 73 idx == 16 ? 4 : 1, "",
67 buf[idx] & 0xff); 74 buf[idx] & 0xff);
68 html(" </td><td class='hex'>"); 75 html(" </td><td class='hex'>");
69 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) 76 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
70 ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.'; 77 ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.';
71 ascii[idx] = '\0'; 78 ascii[idx] = '\0';
72 html_txt(ascii); 79 html_txt(ascii);
73 html("</td></tr>\n"); 80 html("</td></tr>\n");
74 } 81 }
75 html("</table>\n"); 82 html("</table>\n");
76} 83}
77 84
78static void print_object(const unsigned char *sha1, char *path, const char *basename) 85static void print_object(const unsigned char *sha1, char *path, const char *basename)
79{ 86{
80 enum object_type type; 87 enum object_type type;
81 char *buf; 88 char *buf;
82 unsigned long size; 89 unsigned long size;
83 90
84 type = sha1_object_info(sha1, &size); 91 type = sha1_object_info(sha1, &size);
85 if (type == OBJ_BAD) { 92 if (type == OBJ_BAD) {
86 cgit_print_error(fmt("Bad object name: %s", 93 cgit_print_error(fmt("Bad object name: %s",
87 sha1_to_hex(sha1))); 94 sha1_to_hex(sha1)));
88 return; 95 return;
89 } 96 }
90 97
91 buf = read_sha1_file(sha1, &type, &size); 98 buf = read_sha1_file(sha1, &type, &size);
92 if (!buf) { 99 if (!buf) {
93 cgit_print_error(fmt("Error reading object %s", 100 cgit_print_error(fmt("Error reading object %s",
94 sha1_to_hex(sha1))); 101 sha1_to_hex(sha1)));
95 return; 102 return;