aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cgit.c50
-rw-r--r--cgit.h7
-rw-r--r--cgitrc.5.txt60
-rw-r--r--cmd.c42
-rw-r--r--cmd.h3
-rwxr-xr-xfilters/commit-links.sh11
-rwxr-xr-xfilters/syntax-highlighting.sh11
-rw-r--r--html.c15
-rw-r--r--parsing.c29
-rw-r--r--scan-tree.c1
-rw-r--r--shared.c51
-rwxr-xr-xtests/setup.sh25
-rwxr-xr-xtests/t0101-index.sh1
-rwxr-xr-xtests/t0103-log.sh10
-rw-r--r--ui-commit.c6
-rw-r--r--ui-diff.c8
-rw-r--r--ui-log.c29
-rw-r--r--ui-repolist.c4
-rw-r--r--ui-snapshot.c2
-rw-r--r--ui-summary.c2
-rw-r--r--ui-tree.c4
21 files changed, 269 insertions, 102 deletions
diff --git a/cgit.c b/cgit.c
index f4dd6ef..6be3754 100644
--- a/cgit.c
+++ b/cgit.c
@@ -26,18 +26,33 @@ void add_mimetype(const char *name, const char *value)
26 item->util = xstrdup(value); 26 item->util = xstrdup(value);
27} 27}
28 28
29struct cgit_filter *new_filter(const char *cmd, int extra_args) 29struct cgit_filter *new_filter(const char *cmd, filter_type filtertype)
30{ 30{
31 struct cgit_filter *f; 31 struct cgit_filter *f;
32 int args_size = 0;
33 int extra_args;
32 34
33 if (!cmd || !cmd[0]) 35 if (!cmd || !cmd[0])
34 return NULL; 36 return NULL;
35 37
38 switch (filtertype) {
39 case SOURCE:
40 extra_args = 1;
41 break;
42
43 case ABOUT:
44 case COMMIT:
45 default:
46 extra_args = 0;
47 break;
48 }
49
36 f = xmalloc(sizeof(struct cgit_filter)); 50 f = xmalloc(sizeof(struct cgit_filter));
37 f->cmd = xstrdup(cmd); 51 f->cmd = xstrdup(cmd);
38 f->argv = xmalloc((2 + extra_args) * sizeof(char *)); 52 args_size = (2 + extra_args) * sizeof(char *);
53 f->argv = xmalloc(args_size);
54 memset(f->argv, 0, args_size);
39 f->argv[0] = f->cmd; 55 f->argv[0] = f->cmd;
40 f->argv[1] = NULL;
41 return f; 56 return f;
42} 57}
43 58
@@ -81,11 +96,11 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value)
81 repo->logo_link = xstrdup(value); 96 repo->logo_link = xstrdup(value);
82 else if (ctx.cfg.enable_filter_overrides) { 97 else if (ctx.cfg.enable_filter_overrides) {
83 if (!strcmp(name, "about-filter")) 98 if (!strcmp(name, "about-filter"))
84 repo->about_filter = new_filter(value, 0); 99 repo->about_filter = new_filter(value, ABOUT);
85 else if (!strcmp(name, "commit-filter")) 100 else if (!strcmp(name, "commit-filter"))
86 repo->commit_filter = new_filter(value, 0); 101 repo->commit_filter = new_filter(value, COMMIT);
87 else if (!strcmp(name, "source-filter")) 102 else if (!strcmp(name, "source-filter"))
88 repo->source_filter = new_filter(value, 1); 103 repo->source_filter = new_filter(value, SOURCE);
89 } 104 }
90} 105}
91 106
@@ -145,6 +160,8 @@ void config_cb(const char *name, const char *value)
145 ctx.cfg.enable_filter_overrides = atoi(value); 160 ctx.cfg.enable_filter_overrides = atoi(value);
146 else if (!strcmp(name, "enable-gitweb-owner")) 161 else if (!strcmp(name, "enable-gitweb-owner"))
147 ctx.cfg.enable_gitweb_owner = atoi(value); 162 ctx.cfg.enable_gitweb_owner = atoi(value);
163 else if (!strcmp(name, "enable-http-clone"))
164 ctx.cfg.enable_http_clone = atoi(value);
148 else if (!strcmp(name, "enable-index-links")) 165 else if (!strcmp(name, "enable-index-links"))
149 ctx.cfg.enable_index_links = atoi(value); 166 ctx.cfg.enable_index_links = atoi(value);
150 else if (!strcmp(name, "enable-commit-graph")) 167 else if (!strcmp(name, "enable-commit-graph"))
@@ -176,9 +193,9 @@ void config_cb(const char *name, const char *value)
176 else if (!strcmp(name, "cache-dynamic-ttl")) 193 else if (!strcmp(name, "cache-dynamic-ttl"))
177 ctx.cfg.cache_dynamic_ttl = atoi(value); 194 ctx.cfg.cache_dynamic_ttl = atoi(value);
178 else if (!strcmp(name, "about-filter")) 195 else if (!strcmp(name, "about-filter"))
179 ctx.cfg.about_filter = new_filter(value, 0); 196 ctx.cfg.about_filter = new_filter(value, ABOUT);
180 else if (!strcmp(name, "commit-filter")) 197 else if (!strcmp(name, "commit-filter"))
181 ctx.cfg.commit_filter = new_filter(value, 0); 198 ctx.cfg.commit_filter = new_filter(value, COMMIT);
182 else if (!strcmp(name, "embedded")) 199 else if (!strcmp(name, "embedded"))
183 ctx.cfg.embedded = atoi(value); 200 ctx.cfg.embedded = atoi(value);
184 else if (!strcmp(name, "max-atom-items")) 201 else if (!strcmp(name, "max-atom-items"))
@@ -208,7 +225,7 @@ void config_cb(const char *name, const char *value)
208 else if (!strcmp(name, "section-from-path")) 225 else if (!strcmp(name, "section-from-path"))
209 ctx.cfg.section_from_path = atoi(value); 226 ctx.cfg.section_from_path = atoi(value);
210 else if (!strcmp(name, "source-filter")) 227 else if (!strcmp(name, "source-filter"))
211 ctx.cfg.source_filter = new_filter(value, 1); 228 ctx.cfg.source_filter = new_filter(value, SOURCE);
212 else if (!strcmp(name, "summary-log")) 229 else if (!strcmp(name, "summary-log"))
213 ctx.cfg.summary_log = atoi(value); 230 ctx.cfg.summary_log = atoi(value);
214 else if (!strcmp(name, "summary-branches")) 231 else if (!strcmp(name, "summary-branches"))
@@ -310,6 +327,7 @@ static void prepare_context(struct cgit_context *ctx)
310 ctx->cfg.logo = "/cgit.png"; 327 ctx->cfg.logo = "/cgit.png";
311 ctx->cfg.local_time = 0; 328 ctx->cfg.local_time = 0;
312 ctx->cfg.enable_gitweb_owner = 1; 329 ctx->cfg.enable_gitweb_owner = 1;
330 ctx->cfg.enable_http_clone = 1;
313 ctx->cfg.enable_tree_linenumbers = 1; 331 ctx->cfg.enable_tree_linenumbers = 1;
314 ctx->cfg.max_repo_count = 50; 332 ctx->cfg.max_repo_count = 50;
315 ctx->cfg.max_commit_count = 50; 333 ctx->cfg.max_commit_count = 50;
@@ -437,7 +455,7 @@ static int prepare_repo_cmd(struct cgit_context *ctx)
437 tmp = xstrdup(ctx->qry.head); 455 tmp = xstrdup(ctx->qry.head);
438 ctx->qry.head = ctx->repo->defbranch; 456 ctx->qry.head = ctx->repo->defbranch;
439 ctx->page.status = 404; 457 ctx->page.status = 404;
440 ctx->page.statusmsg = "not found"; 458 ctx->page.statusmsg = "Not found";
441 cgit_print_http_headers(ctx); 459 cgit_print_http_headers(ctx);
442 cgit_print_docstart(ctx); 460 cgit_print_docstart(ctx);
443 cgit_print_pageheader(ctx); 461 cgit_print_pageheader(ctx);
@@ -456,6 +474,8 @@ static void process_request(void *cbdata)
456 cmd = cgit_get_cmd(ctx); 474 cmd = cgit_get_cmd(ctx);
457 if (!cmd) { 475 if (!cmd) {
458 ctx->page.title = "cgit error"; 476 ctx->page.title = "cgit error";
477 ctx->page.status = 404;
478 ctx->page.statusmsg = "Not found";
459 cgit_print_http_headers(ctx); 479 cgit_print_http_headers(ctx);
460 cgit_print_docstart(ctx); 480 cgit_print_docstart(ctx);
461 cgit_print_pageheader(ctx); 481 cgit_print_pageheader(ctx);
@@ -464,6 +484,11 @@ static void process_request(void *cbdata)
464 return; 484 return;
465 } 485 }
466 486
487 if (!ctx->cfg.enable_http_clone && cmd->is_clone) {
488 html_status(404, "Not found", 0);
489 return;
490 }
491
467 /* If cmd->want_vpath is set, assume ctx->qry.path contains a "virtual" 492 /* If cmd->want_vpath is set, assume ctx->qry.path contains a "virtual"
468 * in-project path limit to be made available at ctx->qry.vpath. 493 * in-project path limit to be made available at ctx->qry.vpath.
469 * Otherwise, no path limit is in effect (ctx->qry.vpath = NULL). 494 * Otherwise, no path limit is in effect (ctx->qry.vpath = NULL).
@@ -755,8 +780,11 @@ int main(int argc, const char **argv)
755 * that virtual-root equals SCRIPT_NAME, minus any possibly 780 * that virtual-root equals SCRIPT_NAME, minus any possibly
756 * trailing slashes. 781 * trailing slashes.
757 */ 782 */
758 if (!ctx.cfg.virtual_root) 783 if (!ctx.cfg.virtual_root && ctx.cfg.script_name) {
759 ctx.cfg.virtual_root = trim_end(ctx.cfg.script_name, '/'); 784 ctx.cfg.virtual_root = trim_end(ctx.cfg.script_name, '/');
785 if (!ctx.cfg.virtual_root)
786 ctx.cfg.virtual_root = "";
787 }
760 788
761 /* If no url parameter is specified on the querystring, lets 789 /* If no url parameter is specified on the querystring, lets
762 * use PATH_INFO as url. This allows cgit to work with virtual 790 * use PATH_INFO as url. This allows cgit to work with virtual
diff --git a/cgit.h b/cgit.h
index b5f00fc..caa9d8e 100644
--- a/cgit.h
+++ b/cgit.h
@@ -51,6 +51,10 @@ typedef void (*configfn)(const char *name, const char *value);
51typedef void (*filepair_fn)(struct diff_filepair *pair); 51typedef void (*filepair_fn)(struct diff_filepair *pair);
52typedef void (*linediff_fn)(char *line, int len); 52typedef void (*linediff_fn)(char *line, int len);
53 53
54typedef enum {
55 ABOUT, COMMIT, SOURCE
56} filter_type;
57
54struct cgit_filter { 58struct cgit_filter {
55 char *cmd; 59 char *cmd;
56 char **argv; 60 char **argv;
@@ -191,6 +195,7 @@ struct cgit_config {
191 int embedded; 195 int embedded;
192 int enable_filter_overrides; 196 int enable_filter_overrides;
193 int enable_gitweb_owner; 197 int enable_gitweb_owner;
198 int enable_http_clone;
194 int enable_index_links; 199 int enable_index_links;
195 int enable_commit_graph; 200 int enable_commit_graph;
196 int enable_log_filecount; 201 int enable_log_filecount;
@@ -314,7 +319,7 @@ extern const char *cgit_repobasename(const char *reponame);
314 319
315extern int cgit_parse_snapshots_mask(const char *str); 320extern int cgit_parse_snapshots_mask(const char *str);
316 321
317extern int cgit_open_filter(struct cgit_filter *filter); 322extern int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo);
318extern int cgit_close_filter(struct cgit_filter *filter); 323extern int cgit_close_filter(struct cgit_filter *filter);
319 324
320extern int readfile(const char *path, char **buf, size_t *size); 325extern int readfile(const char *path, char **buf, size_t *size);
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index c3698a6..5903a93 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -31,7 +31,7 @@ about-filter::
31 about pages (both top-level and for each repository). The command will 31 about pages (both top-level and for each repository). The command will
32 get the content of the about-file on its STDIN, and the STDOUT from the 32 get the content of the about-file on its STDIN, and the STDOUT from the
33 command will be included verbatim on the about page. Default value: 33 command will be included verbatim on the about page. Default value:
34 none. 34 none. See also: "FILTER API".
35 35
36agefile:: 36agefile::
37 Specifies a path, relative to each repository path, which can be used 37 Specifies a path, relative to each repository path, which can be used
@@ -81,6 +81,7 @@ commit-filter::
81 The command will get the message on its STDIN, and the STDOUT from the 81 The command will get the message on its STDIN, and the STDOUT from the
82 command will be included verbatim as the commit message, i.e. this can 82 command will be included verbatim as the commit message, i.e. this can
83 be used to implement bugtracker integration. Default value: none. 83 be used to implement bugtracker integration. Default value: none.
84 See also: "FILTER API".
84 85
85css:: 86css::
86 Url which specifies the css document to include in all cgit pages. 87 Url which specifies the css document to include in all cgit pages.
@@ -105,6 +106,11 @@ enable-gitweb-owner::
105 for the git config value "gitweb.owner" to determine the owner. 106 for the git config value "gitweb.owner" to determine the owner.
106 Default value: "1". See also: scan-path. 107 Default value: "1". See also: scan-path.
107 108
109enable-http-clone::
110 If set to "1", cgit will act as an dumb HTTP endpoint for git clones.
111 If you use an alternate way of serving git repositories, you may wish
112 to disable this. Default value: "1".
113
108enable-index-links:: 114enable-index-links::
109 Flag which, when set to "1", will make cgit generate extra links for 115 Flag which, when set to "1", will make cgit generate extra links for
110 each repo in the repository index (specifically, to the "summary", 116 each repo in the repository index (specifically, to the "summary",
@@ -287,8 +293,9 @@ scan-path::
287 the result will be cached as a cgitrc include-file in the cache 293 the result will be cached as a cgitrc include-file in the cache
288 directory. If project-list has been defined prior to scan-path, 294 directory. If project-list has been defined prior to scan-path,
289 scan-path loads only the directories listed in the file pointed to by 295 scan-path loads only the directories listed in the file pointed to by
290 project-list. Default value: none. See also: cache-scanrc-ttl, 296 project-list. Be advised that only the global settings taken
291 project-list. 297 before the scan-path directive will be applied to each repository.
298 Default value: none. See also: cache-scanrc-ttl, project-list.
292 299
293section:: 300section::
294 The name of the current repository section - all repositories defined 301 The name of the current repository section - all repositories defined
@@ -308,7 +315,8 @@ side-by-side-diffs::
308snapshots:: 315snapshots::
309 Text which specifies the default set of snapshot formats generated by 316 Text which specifies the default set of snapshot formats generated by
310 cgit. The value is a space-separated list of zero or more of the 317 cgit. The value is a space-separated list of zero or more of the
311 values "tar", "tar.gz", "tar.bz2" and "zip". Default value: none. 318 values "tar", "tar.gz", "tar.bz2", "tar.xz" and "zip". Default value:
319 none.
312 320
313source-filter:: 321source-filter::
314 Specifies a command which will be invoked to format plaintext blobs 322 Specifies a command which will be invoked to format plaintext blobs
@@ -316,7 +324,7 @@ source-filter::
316 and the name of the blob as its only command line argument. The STDOUT 324 and the name of the blob as its only command line argument. The STDOUT
317 from the command will be included verbatim as the blob contents, i.e. 325 from the command will be included verbatim as the blob contents, i.e.
318 this can be used to implement e.g. syntax highlighting. Default value: 326 this can be used to implement e.g. syntax highlighting. Default value:
319 none. 327 none. See also: "FILTER API".
320 328
321summary-branches:: 329summary-branches::
322 Specifies the number of branches to display in the repository "summary" 330 Specifies the number of branches to display in the repository "summary"
@@ -349,7 +357,7 @@ REPOSITORY SETTINGS
349------------------- 357-------------------
350repo.about-filter:: 358repo.about-filter::
351 Override the default about-filter. Default value: none. See also: 359 Override the default about-filter. Default value: none. See also:
352 "enable-filter-overrides". 360 "enable-filter-overrides". See also: "FILTER API".
353 361
354repo.clone-url:: 362repo.clone-url::
355 A list of space-separated urls which can be used to clone this repo. 363 A list of space-separated urls which can be used to clone this repo.
@@ -357,7 +365,7 @@ repo.clone-url::
357 365
358repo.commit-filter:: 366repo.commit-filter::
359 Override the default commit-filter. Default value: none. See also: 367 Override the default commit-filter. Default value: none. See also:
360 "enable-filter-overrides". 368 "enable-filter-overrides". See also: "FILTER API".
361 369
362repo.defbranch:: 370repo.defbranch::
363 The name of the default branch for this repository. If no such branch 371 The name of the default branch for this repository. If no such branch
@@ -428,7 +436,7 @@ repo.section::
428 436
429repo.source-filter:: 437repo.source-filter::
430 Override the default source-filter. Default value: none. See also: 438 Override the default source-filter. Default value: none. See also:
431 "enable-filter-overrides". 439 "enable-filter-overrides". See also: "FILTER API".
432 440
433repo.url:: 441repo.url::
434 The relative url used to access the repository. This must be the first 442 The relative url used to access the repository. This must be the first
@@ -448,6 +456,42 @@ Note: the "repo." prefix is dropped from the option names in repo-specific
448config files, e.g. "repo.desc" becomes "desc". 456config files, e.g. "repo.desc" becomes "desc".
449 457
450 458
459FILTER API
460----------
461- about filter::
462 This filter is given no arguments.
463 The about text that is to be filtered is available on standard input and the
464 filtered text is expected on standard output.
465- commit filter::
466 This filter is given no arguments.
467 The commit message text that is to be filtered is available on standard input
468 and the filtered text is expected on standard output.
469- source filter::
470 This filter is given a single parameter: the filename of the source file to
471 filter. The filter can use the filename to determine (for example) the syntax
472 highlighting mode.
473 The contents of the source file that is to be filtered is available on
474 standard input and the filtered contents is expected on standard output.
475
476Also, all filters are handed the following environment variables:
477- CGIT_REPO_URL ( = repo.url setting )
478- CGIT_REPO_NAME ( = repo.name setting )
479- CGIT_REPO_PATH ( = repo.path setting )
480- CGIT_REPO_OWNER ( = repo.owner setting )
481- CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
482- CGIT_REPO_SECTION ( = section setting )
483- CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
484
485If a setting is not defined for a repository and the corresponding global
486setting is also not defined (if applicable), then the corresponding
487environment variable will be an empty string.
488
489Note that under normal circumstance all these environment variables are
490defined. If however the total size of the defined settings exceed the
491allocated buffer within cgit then only the environment variables that fit
492in the allocated buffer are handed to the filter.
493
494
451EXAMPLE CGITRC FILE 495EXAMPLE CGITRC FILE
452------------------- 496-------------------
453 497
diff --git a/cmd.c b/cmd.c
index 05d5aaf..5a3d157 100644
--- a/cmd.c
+++ b/cmd.c
@@ -130,31 +130,31 @@ static void tree_fn(struct cgit_context *ctx)
130 cgit_print_tree(ctx->qry.sha1, ctx->qry.path); 130 cgit_print_tree(ctx->qry.sha1, ctx->qry.path);
131} 131}
132 132
133#define def_cmd(name, want_repo, want_layout, want_vpath) \ 133#define def_cmd(name, want_repo, want_layout, want_vpath, is_clone) \
134 {#name, name##_fn, want_repo, want_layout, want_vpath} 134 {#name, name##_fn, want_repo, want_layout, want_vpath, is_clone}
135 135
136struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx) 136struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx)
137{ 137{
138 static struct cgit_cmd cmds[] = { 138 static struct cgit_cmd cmds[] = {
139 def_cmd(HEAD, 1, 0, 0), 139 def_cmd(HEAD, 1, 0, 0, 1),
140 def_cmd(atom, 1, 0, 0), 140 def_cmd(atom, 1, 0, 0, 0),
141 def_cmd(about, 0, 1, 0), 141 def_cmd(about, 0, 1, 0, 0),
142 def_cmd(blob, 1, 0, 0), 142 def_cmd(blob, 1, 0, 0, 0),
143 def_cmd(commit, 1, 1, 1), 143 def_cmd(commit, 1, 1, 1, 0),
144 def_cmd(diff, 1, 1, 1), 144 def_cmd(diff, 1, 1, 1, 0),
145 def_cmd(info, 1, 0, 0), 145 def_cmd(info, 1, 0, 0, 1),
146 def_cmd(log, 1, 1, 1), 146 def_cmd(log, 1, 1, 1, 0),
147 def_cmd(ls_cache, 0, 0, 0), 147 def_cmd(ls_cache, 0, 0, 0, 0),
148 def_cmd(objects, 1, 0, 0), 148 def_cmd(objects, 1, 0, 0, 1),
149 def_cmd(patch, 1, 0, 1), 149 def_cmd(patch, 1, 0, 1, 0),
150 def_cmd(plain, 1, 0, 0), 150 def_cmd(plain, 1, 0, 0, 0),
151 def_cmd(refs, 1, 1, 0), 151 def_cmd(refs, 1, 1, 0, 0),
152 def_cmd(repolist, 0, 0, 0), 152 def_cmd(repolist, 0, 0, 0, 0),
153 def_cmd(snapshot, 1, 0, 0), 153 def_cmd(snapshot, 1, 0, 0, 0),
154 def_cmd(stats, 1, 1, 1), 154 def_cmd(stats, 1, 1, 1, 0),
155 def_cmd(summary, 1, 1, 0), 155 def_cmd(summary, 1, 1, 0, 0),
156 def_cmd(tag, 1, 1, 0), 156 def_cmd(tag, 1, 1, 0, 0),
157 def_cmd(tree, 1, 1, 1), 157 def_cmd(tree, 1, 1, 1, 0),
158 }; 158 };
159 int i; 159 int i;
160 160
diff --git a/cmd.h b/cmd.h
index 8dc01bd..eb5bc87 100644
--- a/cmd.h
+++ b/cmd.h
@@ -8,7 +8,8 @@ struct cgit_cmd {
8 cgit_cmd_fn fn; 8 cgit_cmd_fn fn;
9 unsigned int want_repo:1, 9 unsigned int want_repo:1,
10 want_layout:1, 10 want_layout:1,
11 want_vpath:1; 11 want_vpath:1,
12 is_clone:1;
12}; 13};
13 14
14extern struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx); 15extern struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx);
diff --git a/filters/commit-links.sh b/filters/commit-links.sh
index 110c609..d2cd2b3 100755
--- a/filters/commit-links.sh
+++ b/filters/commit-links.sh
@@ -3,6 +3,17 @@
3# 3#
4# To use this script, refer to this file with either the commit-filter or the 4# To use this script, refer to this file with either the commit-filter or the
5# repo.commit-filter options in cgitrc. 5# repo.commit-filter options in cgitrc.
6#
7# The following environment variables can be used to retrieve the configuration
8# of the repository for which this script is called:
9# CGIT_REPO_URL ( = repo.url setting )
10# CGIT_REPO_NAME ( = repo.name setting )
11# CGIT_REPO_PATH ( = repo.path setting )
12# CGIT_REPO_OWNER ( = repo.owner setting )
13# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
14# CGIT_REPO_SECTION ( = section setting )
15# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
16#
6 17
7# This expression generates links to commits referenced by their SHA1. 18# This expression generates links to commits referenced by their SHA1.
8regex=$regex' 19regex=$regex'
diff --git a/filters/syntax-highlighting.sh b/filters/syntax-highlighting.sh
index 6b1c576..6283ce9 100755
--- a/filters/syntax-highlighting.sh
+++ b/filters/syntax-highlighting.sh
@@ -23,6 +23,17 @@
23# table.blob .kwb { color:#830000; } 23# table.blob .kwb { color:#830000; }
24# table.blob .kwc { color:#000000; font-weight:bold; } 24# table.blob .kwc { color:#000000; font-weight:bold; }
25# table.blob .kwd { color:#010181; } 25# table.blob .kwd { color:#010181; }
26#
27# The following environment variables can be used to retrieve the configuration
28# of the repository for which this script is called:
29# CGIT_REPO_URL ( = repo.url setting )
30# CGIT_REPO_NAME ( = repo.name setting )
31# CGIT_REPO_PATH ( = repo.path setting )
32# CGIT_REPO_OWNER ( = repo.owner setting )
33# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
34# CGIT_REPO_SECTION ( = section setting )
35# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
36#
26 37
27# store filename and extension in local vars 38# store filename and extension in local vars
28BASENAME="$1" 39BASENAME="$1"
diff --git a/html.c b/html.c
index ae1cef9..4a18a57 100644
--- a/html.c
+++ b/html.c
@@ -18,7 +18,7 @@ static const char* url_escape_table[256] = {
18 "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", "%08", "%09", 18 "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", "%08", "%09",
19 "%0a", "%0b", "%0c", "%0d", "%0e", "%0f", "%10", "%11", "%12", "%13", 19 "%0a", "%0b", "%0c", "%0d", "%0e", "%0f", "%10", "%11", "%12", "%13",
20 "%14", "%15", "%16", "%17", "%18", "%19", "%1a", "%1b", "%1c", "%1d", 20 "%14", "%15", "%16", "%17", "%18", "%19", "%1a", "%1b", "%1c", "%1d",
21 "%1e", "%1f", "+", 0, "%22", "%23", 0, "%25", "%26", "%27", 0, 0, 0, 21 "%1e", "%1f", "%20", 0, "%22", "%23", 0, "%25", "%26", "%27", 0, 0, 0,
22 "%2b", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "%3c", "%3d", 22 "%2b", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "%3c", "%3d",
23 "%3e", "%3f", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23 "%3e", "%3f", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24 0, 0, 0, 0, 0, 0, 0, 0, 0, "%5c", 0, "%5e", 0, "%60", 0, 0, 0, 0, 0, 24 0, 0, 0, 0, 0, 0, 0, 0, 0, "%5c", 0, "%5e", 0, "%60", 0, 0, 0, 0, 0,
@@ -162,9 +162,9 @@ void html_url_path(const char *txt)
162 while(t && *t){ 162 while(t && *t){
163 int c = *t; 163 int c = *t;
164 const char *e = url_escape_table[c]; 164 const char *e = url_escape_table[c];
165 if (e && c!='+' && c!='&' && c!='+') { 165 if (e && c!='+' && c!='&') {
166 html_raw(txt, t - txt); 166 html_raw(txt, t - txt);
167 html_raw(e, 3); 167 html(e);
168 txt = t+1; 168 txt = t+1;
169 } 169 }
170 t++; 170 t++;
@@ -179,9 +179,11 @@ void html_url_arg(const char *txt)
179 while(t && *t){ 179 while(t && *t){
180 int c = *t; 180 int c = *t;
181 const char *e = url_escape_table[c]; 181 const char *e = url_escape_table[c];
182 if (c == ' ')
183 e = "+";
182 if (e) { 184 if (e) {
183 html_raw(txt, t - txt); 185 html_raw(txt, t - txt);
184 html_raw(e, strlen(e)); 186 html(e);
185 txt = t+1; 187 txt = t+1;
186 } 188 }
187 t++; 189 t++;
@@ -296,12 +298,12 @@ char *convert_query_hexchar(char *txt)
296 298
297int http_parse_querystring(const char *txt_, void (*fn)(const char *name, const char *value)) 299int http_parse_querystring(const char *txt_, void (*fn)(const char *name, const char *value))
298{ 300{
299 char *t, *txt, *value = NULL, c; 301 char *o, *t, *txt, *value = NULL, c;
300 302
301 if (!txt_) 303 if (!txt_)
302 return 0; 304 return 0;
303 305
304 t = txt = strdup(txt_); 306 o = t = txt = strdup(txt_);
305 if (t == NULL) { 307 if (t == NULL) {
306 printf("Out of memory\n"); 308 printf("Out of memory\n");
307 exit(1); 309 exit(1);
@@ -324,5 +326,6 @@ int http_parse_querystring(const char *txt_, void (*fn)(const char *name, const
324 } 326 }
325 if (t!=txt) 327 if (t!=txt)
326 (*fn)(txt, value); 328 (*fn)(txt, value);
329 free(o);
327 return 0; 330 return 0;
328} 331}
diff --git a/parsing.c b/parsing.c
index f37c49d..151c0fe 100644
--- a/parsing.c
+++ b/parsing.c
@@ -103,10 +103,17 @@ const char *reencode(char **txt, const char *src_enc, const char *dst_enc)
103{ 103{
104 char *tmp; 104 char *tmp;
105 105
106 if (!txt || !*txt || !src_enc || !dst_enc) 106 if (!txt)
107 return NULL;
108
109 if (!*txt || !src_enc || !dst_enc)
110 return *txt;
111
112 /* no encoding needed if src_enc equals dst_enc */
113 if(!strcasecmp(src_enc, dst_enc))
107 return *txt; 114 return *txt;
108 115
109 tmp = reencode_string(*txt, src_enc, dst_enc); 116 tmp = reencode_string(*txt, dst_enc, src_enc);
110 if (tmp) { 117 if (tmp) {
111 free(*txt); 118 free(*txt);
112 *txt = tmp; 119 *txt = tmp;
@@ -160,6 +167,10 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
160 } 167 }
161 } 168 }
162 169
170 /* if no special encoding is found, assume UTF-8 */
171 if(!ret->msg_encoding)
172 ret->msg_encoding = xstrdup("UTF-8");
173
163 // skip unknown header fields 174 // skip unknown header fields
164 while (p && *p && (*p != '\n')) { 175 while (p && *p && (*p != '\n')) {
165 p = strchr(p, '\n'); 176 p = strchr(p, '\n');
@@ -189,14 +200,12 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
189 } else 200 } else
190 ret->subject = xstrdup(p); 201 ret->subject = xstrdup(p);
191 202
192 if (ret->msg_encoding) { 203 reencode(&ret->author, ret->msg_encoding, PAGE_ENCODING);
193 reencode(&ret->author, PAGE_ENCODING, ret->msg_encoding); 204 reencode(&ret->author_email, ret->msg_encoding, PAGE_ENCODING);
194 reencode(&ret->author_email, PAGE_ENCODING, ret->msg_encoding); 205 reencode(&ret->committer, ret->msg_encoding, PAGE_ENCODING);
195 reencode(&ret->committer, PAGE_ENCODING, ret->msg_encoding); 206 reencode(&ret->committer_email, ret->msg_encoding, PAGE_ENCODING);
196 reencode(&ret->committer_email, PAGE_ENCODING, ret->msg_encoding); 207 reencode(&ret->subject, ret->msg_encoding, PAGE_ENCODING);
197 reencode(&ret->subject, PAGE_ENCODING, ret->msg_encoding); 208 reencode(&ret->msg, ret->msg_encoding, PAGE_ENCODING);
198 reencode(&ret->msg, PAGE_ENCODING, ret->msg_encoding);
199 }
200 209
201 return ret; 210 return ret;
202} 211}
diff --git a/scan-tree.c b/scan-tree.c
index 627af1b..e5a4baf 100644
--- a/scan-tree.c
+++ b/scan-tree.c
@@ -219,6 +219,7 @@ void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn
219 if (!projects) { 219 if (!projects) {
220 fprintf(stderr, "Error opening projectsfile %s: %s (%d)\n", 220 fprintf(stderr, "Error opening projectsfile %s: %s (%d)\n",
221 projectsfile, strerror(errno), errno); 221 projectsfile, strerror(errno), errno);
222 return;
222 } 223 }
223 while (fgets(line, sizeof(line), projects) != NULL) { 224 while (fgets(line, sizeof(line), projects) != NULL) {
224 for (z = &lastc(line); 225 for (z = &lastc(line);
diff --git a/shared.c b/shared.c
index 7ec2e19..be2ae59 100644
--- a/shared.c
+++ b/shared.c
@@ -7,6 +7,8 @@
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include <stdio.h>
11#include <linux/limits.h>
10 12
11struct cgit_repolist cgit_repolist; 13struct cgit_repolist cgit_repolist;
12struct cgit_context ctx; 14struct cgit_context ctx;
@@ -100,23 +102,15 @@ void *cgit_free_commitinfo(struct commitinfo *info)
100char *trim_end(const char *str, char c) 102char *trim_end(const char *str, char c)
101{ 103{
102 int len; 104 int len;
103 char *s, *t;
104 105
105 if (str == NULL) 106 if (str == NULL)
106 return NULL; 107 return NULL;
107 t = (char *)str; 108 len = strlen(str);
108 len = strlen(t); 109 while(len > 0 && str[len - 1] == c)
109 while(len > 0 && t[len - 1] == c)
110 len--; 110 len--;
111
112 if (len == 0) 111 if (len == 0)
113 return NULL; 112 return NULL;
114 113 return xstrndup(str, len);
115 c = t[len];
116 t[len] = '\0';
117 s = xstrdup(t);
118 t[len] = c;
119 return s;
120} 114}
121 115
122char *strlpart(char *txt, int maxlen) 116char *strlpart(char *txt, int maxlen)
@@ -311,7 +305,6 @@ void cgit_diff_tree(const unsigned char *old_sha1,
311 filepair_fn fn, const char *prefix, int ignorews) 305 filepair_fn fn, const char *prefix, int ignorews)
312{ 306{
313 struct diff_options opt; 307 struct diff_options opt;
314 int ret;
315 int prefixlen; 308 int prefixlen;
316 309
317 diff_setup(&opt); 310 diff_setup(&opt);
@@ -332,9 +325,9 @@ void cgit_diff_tree(const unsigned char *old_sha1,
332 diff_setup_done(&opt); 325 diff_setup_done(&opt);
333 326
334 if (old_sha1 && !is_null_sha1(old_sha1)) 327 if (old_sha1 && !is_null_sha1(old_sha1))
335 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt); 328 diff_tree_sha1(old_sha1, new_sha1, "", &opt);
336 else 329 else
337 ret = diff_root_tree_sha1(new_sha1, "", &opt); 330 diff_root_tree_sha1(new_sha1, "", &opt);
338 diffcore_std(&opt); 331 diffcore_std(&opt);
339 diff_flush(&opt); 332 diff_flush(&opt);
340} 333}
@@ -376,7 +369,33 @@ int cgit_parse_snapshots_mask(const char *str)
376 return rv; 369 return rv;
377} 370}
378 371
379int cgit_open_filter(struct cgit_filter *filter) 372typedef struct {
373 char * name;
374 char * value;
375} cgit_env_var;
376
377static void prepare_env(struct cgit_repo * repo) {
378 cgit_env_var env_vars[] = {
379 { .name = "CGIT_REPO_URL", .value = repo->url },
380 { .name = "CGIT_REPO_NAME", .value = repo->name },
381 { .name = "CGIT_REPO_PATH", .value = repo->path },
382 { .name = "CGIT_REPO_OWNER", .value = repo->owner },
383 { .name = "CGIT_REPO_DEFBRANCH", .value = repo->defbranch },
384 { .name = "CGIT_REPO_SECTION", .value = repo->section },
385 { .name = "CGIT_REPO_CLONE_URL", .value = repo->clone_url }
386 };
387 int env_var_count = ARRAY_SIZE(env_vars);
388 cgit_env_var *p, *q;
389 static char *warn = "cgit warning: failed to set env: %s=%s\n";
390
391 p = env_vars;
392 q = p + env_var_count;
393 for (; p < q; p++)
394 if (setenv(p->name, p->value, 1))
395 fprintf(stderr, warn, p->name, p->value);
396}
397
398int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo)
380{ 399{
381 400
382 filter->old_stdout = chk_positive(dup(STDOUT_FILENO), 401 filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
@@ -387,6 +406,8 @@ int cgit_open_filter(struct cgit_filter *filter)
387 close(filter->pipe_fh[1]); 406 close(filter->pipe_fh[1]);
388 chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO), 407 chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO),
389 "Unable to use pipe as STDIN"); 408 "Unable to use pipe as STDIN");
409 if (repo)
410 prepare_env(repo);
390 execvp(filter->cmd, filter->argv); 411 execvp(filter->cmd, filter->argv);
391 die("Unable to exec subprocess %s: %s (%d)", filter->cmd, 412 die("Unable to exec subprocess %s: %s (%d)", filter->cmd,
392 strerror(errno), errno); 413 strerror(errno), errno);
diff --git a/tests/setup.sh b/tests/setup.sh
index 30f90d5..b2f1169 100755
--- a/tests/setup.sh
+++ b/tests/setup.sh
@@ -20,10 +20,10 @@ mkrepo() {
20 name=$1 20 name=$1
21 count=$2 21 count=$2
22 dir=$PWD 22 dir=$PWD
23 test -d $name && return 23 test -d "$name" && return
24 printf "Creating testrepo %s\n" $name 24 printf "Creating testrepo %s\n" $name
25 mkdir -p $name 25 mkdir -p "$name"
26 cd $name 26 cd "$name"
27 git init 27 git init
28 n=1 28 n=1
29 while test $n -le $count 29 while test $n -le $count
@@ -50,6 +50,7 @@ setup_repos()
50 mkrepo trash/repos/foo 5 >/dev/null 50 mkrepo trash/repos/foo 5 >/dev/null
51 mkrepo trash/repos/bar 50 >/dev/null 51 mkrepo trash/repos/bar 50 >/dev/null
52 mkrepo trash/repos/foo+bar 10 testplus >/dev/null 52 mkrepo trash/repos/foo+bar 10 testplus >/dev/null
53 mkrepo "trash/repos/with space" 2 >/dev/null
53 cat >trash/cgitrc <<EOF 54 cat >trash/cgitrc <<EOF
54virtual-root=/ 55virtual-root=/
55cache-root=$PWD/trash/cache 56cache-root=$PWD/trash/cache
@@ -75,6 +76,10 @@ repo.desc=the bar repo
75repo.url=foo+bar 76repo.url=foo+bar
76repo.path=$PWD/trash/repos/foo+bar/.git 77repo.path=$PWD/trash/repos/foo+bar/.git
77repo.desc=the foo+bar repo 78repo.desc=the foo+bar repo
79
80repo.url=with space
81repo.path=$PWD/trash/repos/with space/.git
82repo.desc=spaced repo
78EOF 83EOF
79} 84}
80 85
@@ -101,6 +106,12 @@ tests_done()
101 106
102run_test() 107run_test()
103{ 108{
109 bug=0
110 if test "$1" = "BUG"
111 then
112 bug=1
113 shift
114 fi
104 desc=$1 115 desc=$1
105 script=$2 116 script=$2
106 test_count=$(expr $test_count + 1) 117 test_count=$(expr $test_count + 1)
@@ -109,9 +120,15 @@ run_test()
109 eval "$2" >>test-output.log 2>>test-output.log 120 eval "$2" >>test-output.log 2>>test-output.log
110 res=$? 121 res=$?
111 printf "test %d: exitcode=%d\n" $test_count $res >>test-output.log 122 printf "test %d: exitcode=%d\n" $test_count $res >>test-output.log
112 if test $res = 0 123 if test $res = 0 -a $bug = 0
113 then 124 then
114 printf " %2d) %-60s [ok]\n" $test_count "$desc" 125 printf " %2d) %-60s [ok]\n" $test_count "$desc"
126 elif test $res = 0 -a $bug = 1
127 then
128 printf " %2d) %-60s [BUG FIXED]\n" $test_count "$desc"
129 elif test $bug = 1
130 then
131 printf " %2d) %-60s [KNOWN BUG]\n" $test_count "$desc"
115 else 132 else
116 test_failed=$(expr $test_failed + 1) 133 test_failed=$(expr $test_failed + 1)
117 printf " %2d) %-60s [failed]\n" $test_count "$desc" 134 printf " %2d) %-60s [failed]\n" $test_count "$desc"
diff --git a/tests/t0101-index.sh b/tests/t0101-index.sh
index 07e39f9..573a351 100755
--- a/tests/t0101-index.sh
+++ b/tests/t0101-index.sh
@@ -11,6 +11,7 @@ run_test 'find bar repo' 'grep -e "bar" trash/tmp'
11run_test 'find bar description' 'grep -e "the bar repo" trash/tmp' 11run_test 'find bar description' 'grep -e "the bar repo" trash/tmp'
12run_test 'find foo+bar repo' 'grep -e ">foo+bar<" trash/tmp' 12run_test 'find foo+bar repo' 'grep -e ">foo+bar<" trash/tmp'
13run_test 'verify foo+bar link' 'grep -e "/foo+bar/" trash/tmp' 13run_test 'verify foo+bar link' 'grep -e "/foo+bar/" trash/tmp'
14run_test 'verify "with%20space" link' 'grep -e "/with%20space/" trash/tmp'
14run_test 'no tree-link' '! grep -e "foo/tree" trash/tmp' 15run_test 'no tree-link' '! grep -e "foo/tree" trash/tmp'
15run_test 'no log-link' '! grep -e "foo/log" trash/tmp' 16run_test 'no log-link' '! grep -e "foo/log" trash/tmp'
16 17
diff --git a/tests/t0103-log.sh b/tests/t0103-log.sh
index b08cd29..def5c18 100755
--- a/tests/t0103-log.sh
+++ b/tests/t0103-log.sh
@@ -12,4 +12,14 @@ run_test 'generate bar/log' 'cgit_url "bar/log" >trash/tmp'
12run_test 'find commit 1' 'grep -e "commit 1" trash/tmp' 12run_test 'find commit 1' 'grep -e "commit 1" trash/tmp'
13run_test 'find commit 50' 'grep -e "commit 50" trash/tmp' 13run_test 'find commit 50' 'grep -e "commit 50" trash/tmp'
14 14
15run_test 'generate "with%20space/log?qt=grep&q=commit+1"' '
16 cgit_url "with+space/log&qt=grep&q=commit+1" >trash/tmp
17'
18run_test 'find commit 1' 'grep -e "commit 1" trash/tmp'
19run_test 'find link with %20 in path' 'grep -e "/with%20space/log/?qt=grep" trash/tmp'
20run_test 'find link with + in arg' 'grep -e "/log/?qt=grep&q=commit+1" trash/tmp'
21run_test BUG 'no links with space in path' '! grep -e "href=./with space/" trash/tmp'
22run_test 'no links with space in arg' '! grep -e "q=commit 1" trash/tmp'
23run_test 'commit 2 is not visible' '! grep -e "commit 2" trash/tmp'
24
15tests_done 25tests_done
diff --git a/ui-commit.c b/ui-commit.c
index 536a8e8..a69dec6 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -106,7 +106,7 @@ void cgit_print_commit(char *hex, const char *prefix)
106 html("</table>\n"); 106 html("</table>\n");
107 html("<div class='commit-subject'>"); 107 html("<div class='commit-subject'>");
108 if (ctx.repo->commit_filter) 108 if (ctx.repo->commit_filter)
109 cgit_open_filter(ctx.repo->commit_filter); 109 cgit_open_filter(ctx.repo->commit_filter, ctx.repo);
110 html_txt(info->subject); 110 html_txt(info->subject);
111 if (ctx.repo->commit_filter) 111 if (ctx.repo->commit_filter)
112 cgit_close_filter(ctx.repo->commit_filter); 112 cgit_close_filter(ctx.repo->commit_filter);
@@ -114,7 +114,7 @@ void cgit_print_commit(char *hex, const char *prefix)
114 html("</div>"); 114 html("</div>");
115 html("<div class='commit-msg'>"); 115 html("<div class='commit-msg'>");
116 if (ctx.repo->commit_filter) 116 if (ctx.repo->commit_filter)
117 cgit_open_filter(ctx.repo->commit_filter); 117 cgit_open_filter(ctx.repo->commit_filter, ctx.repo);
118 html_txt(info->msg); 118 html_txt(info->msg);
119 if (ctx.repo->commit_filter) 119 if (ctx.repo->commit_filter)
120 cgit_close_filter(ctx.repo->commit_filter); 120 cgit_close_filter(ctx.repo->commit_filter);
@@ -123,7 +123,7 @@ void cgit_print_commit(char *hex, const char *prefix)
123 html("<div class='notes-header'>Notes</div>"); 123 html("<div class='notes-header'>Notes</div>");
124 html("<div class='notes'>"); 124 html("<div class='notes'>");
125 if (ctx.repo->commit_filter) 125 if (ctx.repo->commit_filter)
126 cgit_open_filter(ctx.repo->commit_filter); 126 cgit_open_filter(ctx.repo->commit_filter, ctx.repo);
127 html_txt(notes.buf); 127 html_txt(notes.buf);
128 if (ctx.repo->commit_filter) 128 if (ctx.repo->commit_filter)
129 cgit_close_filter(ctx.repo->commit_filter); 129 cgit_close_filter(ctx.repo->commit_filter);
diff --git a/ui-diff.c b/ui-diff.c
index b7767b3..868ceec 100644
--- a/ui-diff.c
+++ b/ui-diff.c
@@ -368,8 +368,10 @@ void cgit_print_diff(const char *new_rev, const char *old_rev,
368 return; 368 return;
369 } 369 }
370 commit = lookup_commit_reference(new_rev_sha1); 370 commit = lookup_commit_reference(new_rev_sha1);
371 if (!commit || parse_commit(commit)) 371 if (!commit || parse_commit(commit)) {
372 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(new_rev_sha1))); 372 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(new_rev_sha1)));
373 return;
374 }
373 375
374 if (old_rev) 376 if (old_rev)
375 get_sha1(old_rev, old_rev_sha1); 377 get_sha1(old_rev, old_rev_sha1);
@@ -385,8 +387,10 @@ void cgit_print_diff(const char *new_rev, const char *old_rev,
385 return; 387 return;
386 } 388 }
387 commit2 = lookup_commit_reference(old_rev_sha1); 389 commit2 = lookup_commit_reference(old_rev_sha1);
388 if (!commit2 || parse_commit(commit2)) 390 if (!commit2 || parse_commit(commit2)) {
389 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(old_rev_sha1))); 391 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(old_rev_sha1)));
392 return;
393 }
390 } 394 }
391 395
392 if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff)) 396 if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff))
diff --git a/ui-log.c b/ui-log.c
index 8add66a..2e6e9d6 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -100,11 +100,10 @@ void print_commit(struct commit *commit, struct rev_info *revs)
100 struct strbuf graphbuf = STRBUF_INIT; 100 struct strbuf graphbuf = STRBUF_INIT;
101 struct strbuf msgbuf = STRBUF_INIT; 101 struct strbuf msgbuf = STRBUF_INIT;
102 102
103 if (ctx.repo->enable_log_filecount) { 103 if (ctx.repo->enable_log_filecount)
104 cols++;
105 if (ctx.repo->enable_log_linecount)
104 cols++; 106 cols++;
105 if (ctx.repo->enable_log_linecount)
106 cols++;
107 }
108 107
109 if (revs->graph) { 108 if (revs->graph) {
110 /* Advance graph until current commit */ 109 /* Advance graph until current commit */
@@ -179,18 +178,18 @@ void print_commit(struct commit *commit, struct rev_info *revs)
179 html_link_close(); 178 html_link_close();
180 } 179 }
181 180
182 if (ctx.repo->enable_log_filecount) { 181 if (ctx.repo->enable_log_filecount || ctx.repo->enable_log_linecount) {
183 files = 0; 182 files = 0;
184 add_lines = 0; 183 add_lines = 0;
185 rem_lines = 0; 184 rem_lines = 0;
186 cgit_diff_commit(commit, inspect_files, ctx.qry.vpath); 185 cgit_diff_commit(commit, inspect_files, ctx.qry.vpath);
187 html("</td><td>");
188 htmlf("%d", files);
189 if (ctx.repo->enable_log_linecount) {
190 html("</td><td>");
191 htmlf("-%d/+%d", rem_lines, add_lines);
192 }
193 } 186 }
187
188 if (ctx.repo->enable_log_filecount)
189 htmlf("</td><td>%d", files);
190 if (ctx.repo->enable_log_linecount)
191 htmlf("</td><td>-%d/+%d", rem_lines, add_lines);
192
194 html("</td></tr>\n"); 193 html("</td></tr>\n");
195 194
196 if (revs->graph || ctx.qry.showmsg) { /* Print a second table row */ 195 if (revs->graph || ctx.qry.showmsg) { /* Print a second table row */
@@ -379,10 +378,10 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern
379 if (ctx.repo->enable_log_filecount) { 378 if (ctx.repo->enable_log_filecount) {
380 html("<th class='left'>Files</th>"); 379 html("<th class='left'>Files</th>");
381 columns++; 380 columns++;
382 if (ctx.repo->enable_log_linecount) { 381 }
383 html("<th class='left'>Lines</th>"); 382 if (ctx.repo->enable_log_linecount) {
384 columns++; 383 html("<th class='left'>Lines</th>");
385 } 384 columns++;
386 } 385 }
387 html("</tr>\n"); 386 html("</tr>\n");
388 387
diff --git a/ui-repolist.c b/ui-repolist.c
index 2c98668..6f304bb 100644
--- a/ui-repolist.c
+++ b/ui-repolist.c
@@ -20,7 +20,7 @@ time_t read_agefile(char *path)
20 if (readfile(path, &buf, &size)) 20 if (readfile(path, &buf, &size))
21 return -1; 21 return -1;
22 22
23 if (parse_date(buf, buf2, sizeof(buf2))) 23 if (parse_date(buf, buf2, sizeof(buf2)) > 0)
24 result = strtoul(buf2, NULL, 10); 24 result = strtoul(buf2, NULL, 10);
25 else 25 else
26 result = 0; 26 result = 0;
@@ -291,7 +291,7 @@ void cgit_print_site_readme()
291 if (!ctx.cfg.root_readme) 291 if (!ctx.cfg.root_readme)
292 return; 292 return;
293 if (ctx.cfg.about_filter) 293 if (ctx.cfg.about_filter)
294 cgit_open_filter(ctx.cfg.about_filter); 294 cgit_open_filter(ctx.cfg.about_filter, NULL);
295 html_include(ctx.cfg.root_readme); 295 html_include(ctx.cfg.root_readme);
296 if (ctx.cfg.about_filter) 296 if (ctx.cfg.about_filter)
297 cgit_close_filter(ctx.cfg.about_filter); 297 cgit_close_filter(ctx.cfg.about_filter);
diff --git a/ui-snapshot.c b/ui-snapshot.c
index 6e3412c..067082c 100644
--- a/ui-snapshot.c
+++ b/ui-snapshot.c
@@ -19,7 +19,7 @@ static int write_compressed_tar_archive(struct archiver_args *args,const char *f
19 f.argv = malloc(2 * sizeof(char *)); 19 f.argv = malloc(2 * sizeof(char *));
20 f.argv[0] = f.cmd; 20 f.argv[0] = f.cmd;
21 f.argv[1] = NULL; 21 f.argv[1] = NULL;
22 cgit_open_filter(&f); 22 cgit_open_filter(&f, NULL);
23 rv = write_tar_archive(args); 23 rv = write_tar_archive(args);
24 cgit_close_filter(&f); 24 cgit_close_filter(&f);
25 return rv; 25 return rv;
diff --git a/ui-summary.c b/ui-summary.c
index 5be2545..1e9a1b6 100644
--- a/ui-summary.c
+++ b/ui-summary.c
@@ -113,7 +113,7 @@ void cgit_print_repo_readme(char *path)
113 */ 113 */
114 html("<div id='summary'>"); 114 html("<div id='summary'>");
115 if (ctx.repo->about_filter) 115 if (ctx.repo->about_filter)
116 cgit_open_filter(ctx.repo->about_filter); 116 cgit_open_filter(ctx.repo->about_filter, ctx.repo);
117 if (ref) 117 if (ref)
118 cgit_print_file(tmp, ref); 118 cgit_print_file(tmp, ref);
119 else 119 else
diff --git a/ui-tree.c b/ui-tree.c
index 0b1b531..2d8d2f3 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -45,9 +45,11 @@ static void print_text_buffer(const char *name, char *buf, unsigned long size)
45 if (ctx.repo->source_filter) { 45 if (ctx.repo->source_filter) {
46 html("<td class='lines'><pre><code>"); 46 html("<td class='lines'><pre><code>");
47 ctx.repo->source_filter->argv[1] = xstrdup(name); 47 ctx.repo->source_filter->argv[1] = xstrdup(name);
48 cgit_open_filter(ctx.repo->source_filter); 48 cgit_open_filter(ctx.repo->source_filter, ctx.repo);
49 html_raw(buf, size); 49 html_raw(buf, size);
50 cgit_close_filter(ctx.repo->source_filter); 50 cgit_close_filter(ctx.repo->source_filter);
51 free(ctx.repo->source_filter->argv[1]);
52 ctx.repo->source_filter->argv[1] = NULL;
51 html("</code></pre></td></tr></table>\n"); 53 html("</code></pre></td></tr></table>\n");
52 return; 54 return;
53 } 55 }