summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--.gitignore5
-rw-r--r--Makefile21
-rw-r--r--cgit-doc.css3
-rw-r--r--cgit.c87
-rw-r--r--cgit.css2
-rw-r--r--cgit.h41
-rw-r--r--cgitrc.5.txt185
-rw-r--r--cmd.c2
-rwxr-xr-xfilters/commit-links.sh12
-rwxr-xr-xfilters/syntax-highlighting.sh39
m---------git0
-rw-r--r--shared.c38
-rw-r--r--ui-atom.c8
-rw-r--r--ui-blob.c8
-rw-r--r--ui-commit.c12
-rw-r--r--ui-log.c4
-rw-r--r--ui-patch.c6
-rw-r--r--ui-plain.c16
-rw-r--r--ui-refs.c19
-rw-r--r--ui-repolist.c7
-rw-r--r--ui-shared.c79
-rw-r--r--ui-shared.h1
-rw-r--r--ui-snapshot.c35
-rw-r--r--ui-summary.c24
-rw-r--r--ui-summary.h2
-rw-r--r--ui-tag.c2
-rw-r--r--ui-tree.c26
27 files changed, 543 insertions, 141 deletions
diff --git a/.gitignore b/.gitignore
index 1e016e5..487728b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,2 +4,7 @@ cgit.conf
4VERSION 4VERSION
5cgitrc.5
6cgitrc.5.fo
7cgitrc.5.html
8cgitrc.5.pdf
9cgitrc.5.xml
5*.o 10*.o
diff --git a/Makefile b/Makefile
index 33c606d..1f9893a 100644
--- a/Makefile
+++ b/Makefile
@@ -7,3 +7,3 @@ CACHE_ROOT = /var/cache/cgit
7SHA1_HEADER = <openssl/sha.h> 7SHA1_HEADER = <openssl/sha.h>
8GIT_VER = 1.6.1.1 8GIT_VER = 1.6.3.4
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
@@ -102,3 +102,4 @@ endif
102 102
103.PHONY: all libgit test install uninstall clean force-version get-git 103.PHONY: all libgit test install uninstall clean force-version get-git \
104 doc man-doc html-doc clean-doc
104 105
@@ -151,5 +152,19 @@ uninstall:
151 152
152clean: 153doc: man-doc html-doc pdf-doc
154
155man-doc: cgitrc.5.txt
156 a2x -f manpage cgitrc.5.txt
157
158html-doc: cgitrc.5.txt
159 a2x -f xhtml --stylesheet=cgit-doc.css cgitrc.5.txt
160
161pdf-doc: cgitrc.5.txt
162 a2x -f pdf cgitrc.5.txt
163
164clean: clean-doc
153 rm -f cgit VERSION *.o *.d 165 rm -f cgit VERSION *.o *.d
154 166
167clean-doc:
168 rm -f cgitrc.5 cgitrc.5.html cgitrc.5.pdf cgitrc.5.xml cgitrc.5.fo
169
155get-git: 170get-git:
diff --git a/cgit-doc.css b/cgit-doc.css
new file mode 100644
index 0000000..5a399b6
--- a/dev/null
+++ b/cgit-doc.css
@@ -0,0 +1,3 @@
1div.variablelist dt {
2 margin-top: 1em;
3}
diff --git a/cgit.c b/cgit.c
index 5301840..5816f3d 100644
--- a/cgit.c
+++ b/cgit.c
@@ -19,2 +19,25 @@ const char *cgit_version = CGIT_VERSION;
19 19
20void add_mimetype(const char *name, const char *value)
21{
22 struct string_list_item *item;
23
24 item = string_list_insert(xstrdup(name), &ctx.cfg.mimetypes);
25 item->util = xstrdup(value);
26}
27
28struct cgit_filter *new_filter(const char *cmd, int extra_args)
29{
30 struct cgit_filter *f;
31
32 if (!cmd || !cmd[0])
33 return NULL;
34
35 f = xmalloc(sizeof(struct cgit_filter));
36 f->cmd = xstrdup(cmd);
37 f->argv = xmalloc((2 + extra_args) * sizeof(char *));
38 f->argv[0] = f->cmd;
39 f->argv[1] = NULL;
40 return f;
41}
42
20void config_cb(const char *name, const char *value) 43void config_cb(const char *name, const char *value)
@@ -33,2 +56,4 @@ void config_cb(const char *name, const char *value)
33 ctx.cfg.footer = xstrdup(value); 56 ctx.cfg.footer = xstrdup(value);
57 else if (!strcmp(name, "head-include"))
58 ctx.cfg.head_include = xstrdup(value);
34 else if (!strcmp(name, "header")) 59 else if (!strcmp(name, "header"))
@@ -51,2 +76,6 @@ void config_cb(const char *name, const char *value)
51 ctx.cfg.nocache = atoi(value); 76 ctx.cfg.nocache = atoi(value);
77 else if (!strcmp(name, "noplainemail"))
78 ctx.cfg.noplainemail = atoi(value);
79 else if (!strcmp(name, "noheader"))
80 ctx.cfg.noheader = atoi(value);
52 else if (!strcmp(name, "snapshots")) 81 else if (!strcmp(name, "snapshots"))
@@ -73,2 +102,8 @@ void config_cb(const char *name, const char *value)
73 ctx.cfg.cache_dynamic_ttl = atoi(value); 102 ctx.cfg.cache_dynamic_ttl = atoi(value);
103 else if (!strcmp(name, "about-filter"))
104 ctx.cfg.about_filter = new_filter(value, 0);
105 else if (!strcmp(name, "commit-filter"))
106 ctx.cfg.commit_filter = new_filter(value, 0);
107 else if (!strcmp(name, "embedded"))
108 ctx.cfg.embedded = atoi(value);
74 else if (!strcmp(name, "max-message-length")) 109 else if (!strcmp(name, "max-message-length"))
@@ -81,2 +116,4 @@ void config_cb(const char *name, const char *value)
81 ctx.cfg.max_commit_count = atoi(value); 116 ctx.cfg.max_commit_count = atoi(value);
117 else if (!strcmp(name, "source-filter"))
118 ctx.cfg.source_filter = new_filter(value, 1);
82 else if (!strcmp(name, "summary-log")) 119 else if (!strcmp(name, "summary-log"))
@@ -97,2 +134,4 @@ void config_cb(const char *name, const char *value)
97 ctx.cfg.local_time = atoi(value); 134 ctx.cfg.local_time = atoi(value);
135 else if (!prefixcmp(name, "mimetype."))
136 add_mimetype(name + 9, value);
98 else if (!strcmp(name, "repo.group")) 137 else if (!strcmp(name, "repo.group"))
@@ -123,2 +162,8 @@ void config_cb(const char *name, const char *value)
123 ctx.repo->module_link= xstrdup(value); 162 ctx.repo->module_link= xstrdup(value);
163 else if (ctx.repo && !strcmp(name, "repo.about-filter"))
164 ctx.repo->about_filter = new_filter(value, 0);
165 else if (ctx.repo && !strcmp(name, "repo.commit-filter"))
166 ctx.repo->commit_filter = new_filter(value, 0);
167 else if (ctx.repo && !strcmp(name, "repo.source-filter"))
168 ctx.repo->source_filter = new_filter(value, 1);
124 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { 169 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
@@ -175,2 +220,7 @@ static void querystring_cb(const char *name, const char *value)
175 220
221char *xstrdupn(const char *str)
222{
223 return (str ? xstrdup(str) : NULL);
224}
225
176static void prepare_context(struct cgit_context *ctx) 226static void prepare_context(struct cgit_context *ctx)
@@ -188,3 +238,3 @@ static void prepare_context(struct cgit_context *ctx)
188 ctx->cfg.css = "/cgit.css"; 238 ctx->cfg.css = "/cgit.css";
189 ctx->cfg.logo = "/git-logo.png"; 239 ctx->cfg.logo = "/cgit.png";
190 ctx->cfg.local_time = 0; 240 ctx->cfg.local_time = 0;
@@ -205,2 +255,12 @@ static void prepare_context(struct cgit_context *ctx)
205 ctx->cfg.summary_tags = 10; 255 ctx->cfg.summary_tags = 10;
256 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));
257 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST"));
258 ctx->env.https = xstrdupn(getenv("HTTPS"));
259 ctx->env.no_http = xstrdupn(getenv("NO_HTTP"));
260 ctx->env.path_info = xstrdupn(getenv("PATH_INFO"));
261 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING"));
262 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD"));
263 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
264 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME"));
265 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT"));
206 ctx->page.mimetype = "text/html"; 266 ctx->page.mimetype = "text/html";
@@ -211,2 +271,10 @@ static void prepare_context(struct cgit_context *ctx)
211 ctx->page.expires = ctx->page.modified; 271 ctx->page.expires = ctx->page.modified;
272 ctx->page.etag = NULL;
273 memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list));
274 if (ctx->env.script_name)
275 ctx->cfg.script_name = ctx->env.script_name;
276 if (ctx->env.query_string)
277 ctx->qry.raw = ctx->env.query_string;
278 if (!ctx->env.cgit_config)
279 ctx->env.cgit_config = CGIT_CONFIG;
212} 280}
@@ -290,2 +358,4 @@ static int prepare_repo_cmd(struct cgit_context *ctx)
290 ctx->qry.head = ctx->repo->defbranch; 358 ctx->qry.head = ctx->repo->defbranch;
359 ctx->page.status = 404;
360 ctx->page.statusmsg = "not found";
291 cgit_print_http_headers(ctx); 361 cgit_print_http_headers(ctx);
@@ -381,2 +451,5 @@ static void cgit_parse_args(int argc, const char **argv)
381 } 451 }
452 if (!strcmp(argv[i], "--nohttp")) {
453 ctx.env.no_http = "1";
454 }
382 if (!strncmp(argv[i], "--query=", 8)) { 455 if (!strncmp(argv[i], "--query=", 8)) {
@@ -433,3 +506,2 @@ int main(int argc, const char **argv)
433{ 506{
434 const char *cgit_config_env = getenv("CGIT_CONFIG");
435 const char *path; 507 const char *path;
@@ -443,9 +515,4 @@ int main(int argc, const char **argv)
443 515
444 if (getenv("SCRIPT_NAME"))
445 ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME"));
446 if (getenv("QUERY_STRING"))
447 ctx.qry.raw = xstrdup(getenv("QUERY_STRING"));
448 cgit_parse_args(argc, argv); 516 cgit_parse_args(argc, argv);
449 parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG, 517 parse_configfile(ctx.env.cgit_config, config_cb);
450 config_cb);
451 ctx.repo = NULL; 518 ctx.repo = NULL;
@@ -464,3 +531,3 @@ int main(int argc, const char **argv)
464 */ 531 */
465 path = getenv("PATH_INFO"); 532 path = ctx.env.path_info;
466 if (!ctx.qry.url && path) { 533 if (!ctx.qry.url && path) {
@@ -480,2 +547,4 @@ int main(int argc, const char **argv)
480 ctx.page.expires += ttl*60; 547 ctx.page.expires += ttl*60;
548 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))
549 ctx.cfg.nocache = 1;
481 if (ctx.cfg.nocache) 550 if (ctx.cfg.nocache)
diff --git a/cgit.css b/cgit.css
index adfc8ae..e3b32e7 100644
--- a/cgit.css
+++ b/cgit.css
@@ -157,3 +157,3 @@ table.list td.logmsg {
157 white-space: pre; 157 white-space: pre;
158 padding: 1em 0em 2em 0em; 158 padding: 1em 0.5em 2em 0.5em;
159} 159}
diff --git a/cgit.h b/cgit.h
index 5f7af51..d90ccdc 100644
--- a/cgit.h
+++ b/cgit.h
@@ -17,2 +17,3 @@
17#include <archive.h> 17#include <archive.h>
18#include <string-list.h>
18#include <xdiff-interface.h> 19#include <xdiff-interface.h>
@@ -50,2 +51,11 @@ typedef void (*linediff_fn)(char *line, int len);
50 51
52struct cgit_filter {
53 char *cmd;
54 char **argv;
55 int old_stdout;
56 int pipe_fh[2];
57 int pid;
58 int exitstatus;
59};
60
51struct cgit_repo { 61struct cgit_repo {
@@ -66,2 +76,5 @@ struct cgit_repo {
66 time_t mtime; 76 time_t mtime;
77 struct cgit_filter *about_filter;
78 struct cgit_filter *commit_filter;
79 struct cgit_filter *source_filter;
67}; 80};
@@ -138,2 +151,3 @@ struct cgit_config {
138 char *footer; 151 char *footer;
152 char *head_include;
139 char *header; 153 char *header;
@@ -157,2 +171,3 @@ struct cgit_config {
157 int cache_static_ttl; 171 int cache_static_ttl;
172 int embedded;
158 int enable_index_links; 173 int enable_index_links;
@@ -168,2 +183,4 @@ struct cgit_config {
168 int nocache; 183 int nocache;
184 int noplainemail;
185 int noheader;
169 int renamelimit; 186 int renamelimit;
@@ -173,2 +190,6 @@ struct cgit_config {
173 int summary_tags; 190 int summary_tags;
191 struct string_list mimetypes;
192 struct cgit_filter *about_filter;
193 struct cgit_filter *commit_filter;
194 struct cgit_filter *source_filter;
174}; 195};
@@ -182,3 +203,19 @@ struct cgit_page {
182 char *filename; 203 char *filename;
204 char *etag;
183 char *title; 205 char *title;
206 int status;
207 char *statusmsg;
208};
209
210struct cgit_environment {
211 char *cgit_config;
212 char *http_host;
213 char *https;
214 char *no_http;
215 char *path_info;
216 char *query_string;
217 char *request_method;
218 char *script_name;
219 char *server_name;
220 char *server_port;
184}; 221};
@@ -186,2 +223,3 @@ struct cgit_page {
186struct cgit_context { 223struct cgit_context {
224 struct cgit_environment env;
187 struct cgit_query qry; 225 struct cgit_query qry;
@@ -244,2 +282,5 @@ extern int cgit_parse_snapshots_mask(const char *str);
244 282
283extern int cgit_open_filter(struct cgit_filter *filter);
284extern int cgit_close_filter(struct cgit_filter *filter);
285
245 286
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index fd299ae..3c35b02 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -1,3 +1,3 @@
1CGITRC 1CGITRC(5)
2====== 2========
3 3
@@ -9,4 +9,4 @@ NAME
9 9
10DESCRIPTION 10SYNOPSIS
11----------- 11--------
12Cgitrc contains all runtime settings for cgit, including the list of git 12Cgitrc contains all runtime settings for cgit, including the list of git
@@ -16,5 +16,19 @@ lines, and lines starting with '#', are ignored.
16 16
17LOCATION
18--------
19The default location of cgitrc, defined at compile time, is /etc/cgitrc. At
20runtime, cgit will consult the environment variable CGIT_CONFIG and, if
21defined, use its value instead.
22
23
17GLOBAL SETTINGS 24GLOBAL SETTINGS
18--------------- 25---------------
19agefile 26about-filter::
27 Specifies a command which will be invoked to format the content of
28 about pages (both top-level and for each repository). The command will
29 get the content of the about-file on its STDIN, and the STDOUT from the
30 command will be included verbatim on the about page. Default value:
31 none.
32
33agefile::
20 Specifies a path, relative to each repository path, which can be used 34 Specifies a path, relative to each repository path, which can be used
@@ -25,3 +39,3 @@ agefile
25 39
26cache-root 40cache-root::
27 Path used to store the cgit cache entries. Default value: 41 Path used to store the cgit cache entries. Default value:
@@ -29,3 +43,3 @@ cache-root
29 43
30cache-dynamic-ttl 44cache-dynamic-ttl::
31 Number which specifies the time-to-live, in minutes, for the cached 45 Number which specifies the time-to-live, in minutes, for the cached
@@ -34,3 +48,3 @@ cache-dynamic-ttl
34 48
35cache-repo-ttl 49cache-repo-ttl::
36 Number which specifies the time-to-live, in minutes, for the cached 50 Number which specifies the time-to-live, in minutes, for the cached
@@ -38,3 +52,3 @@ cache-repo-ttl
38 52
39cache-root-ttl 53cache-root-ttl::
40 Number which specifies the time-to-live, in minutes, for the cached 54 Number which specifies the time-to-live, in minutes, for the cached
@@ -42,3 +56,3 @@ cache-root-ttl
42 56
43cache-size 57cache-size::
44 The maximum number of entries in the cgit cache. Default value: "0" 58 The maximum number of entries in the cgit cache. Default value: "0"
@@ -46,3 +60,3 @@ cache-size
46 60
47cache-static-ttl 61cache-static-ttl::
48 Number which specifies the time-to-live, in minutes, for the cached 62 Number which specifies the time-to-live, in minutes, for the cached
@@ -51,3 +65,3 @@ cache-static-ttl
51 65
52clone-prefix 66clone-prefix::
53 Space-separated list of common prefixes which, when combined with a 67 Space-separated list of common prefixes which, when combined with a
@@ -57,3 +71,9 @@ clone-prefix
57 71
58css 72commit-filter::
73 Specifies a command which will be invoked to format commit messages.
74 The command will get the message on its STDIN, and the STDOUT from the
75 command will be included verbatim as the commit message, i.e. this can
76 be used to implement bugtracker integration. Default value: none.
77
78css::
59 Url which specifies the css document to include in all cgit pages. 79 Url which specifies the css document to include in all cgit pages.
@@ -61,3 +81,8 @@ css
61 81
62enable-index-links 82embedded::
83 Flag which, when set to "1", will make cgit generate a html fragment
84 suitable for embedding in other html pages. Default value: none. See
85 also: "noheader".
86
87enable-index-links::
63 Flag which, when set to "1", will make cgit generate extra links for 88 Flag which, when set to "1", will make cgit generate extra links for
@@ -66,3 +91,3 @@ enable-index-links
66 91
67enable-log-filecount 92enable-log-filecount::
68 Flag which, when set to "1", will make cgit print the number of 93 Flag which, when set to "1", will make cgit print the number of
@@ -71,3 +96,3 @@ enable-log-filecount
71 96
72enable-log-linecount 97enable-log-linecount::
73 Flag which, when set to "1", will make cgit print the number of added 98 Flag which, when set to "1", will make cgit print the number of added
@@ -76,3 +101,3 @@ enable-log-linecount
76 101
77favicon 102favicon::
78 Url used as link to a shortcut icon for cgit. If specified, it is 103 Url used as link to a shortcut icon for cgit. If specified, it is
@@ -81,3 +106,3 @@ favicon
81 106
82footer 107footer::
83 The content of the file specified with this option will be included 108 The content of the file specified with this option will be included
@@ -86,3 +111,7 @@ footer
86 111
87header 112head-include::
113 The content of the file specified with this option will be included
114 verbatim in the html HEAD section on all pages. Default value: none.
115
116header::
88 The content of the file specified with this option will be included 117 The content of the file specified with this option will be included
@@ -90,3 +119,3 @@ header
90 119
91include 120include::
92 Name of a configfile to include before the rest of the current config- 121 Name of a configfile to include before the rest of the current config-
@@ -94,3 +123,3 @@ include
94 123
95index-header 124index-header::
96 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
@@ -100,3 +129,3 @@ index-header
100 129
101index-info 130index-info::
102 The content of the file specified with this option will be included 131 The content of the file specified with this option will be included
@@ -106,3 +135,3 @@ index-info
106 135
107local-time 136local-time::
108 Flag which, if set to "1", makes cgit print commit and tag times in the 137 Flag which, if set to "1", makes cgit print commit and tag times in the
@@ -110,7 +139,7 @@ local-time
110 139
111logo 140logo::
112 Url which specifies the source of an image which will be used as a logo 141 Url which specifies the source of an image which will be used as a logo
113 on all cgit pages. 142 on all cgit pages. Default value: "/cgit.png".
114 143
115logo-link 144logo-link::
116 Url loaded when clicking on the cgit logo image. If unspecified the 145 Url loaded when clicking on the cgit logo image. If unspecified the
@@ -119,3 +148,3 @@ logo-link
119 148
120max-commit-count 149max-commit-count::
121 Specifies the number of entries to list per page in "log" view. Default 150 Specifies the number of entries to list per page in "log" view. Default
@@ -123,3 +152,3 @@ max-commit-count
123 152
124max-message-length 153max-message-length::
125 Specifies the maximum number of commit message characters to display in 154 Specifies the maximum number of commit message characters to display in
@@ -127,3 +156,3 @@ max-message-length
127 156
128max-repo-count 157max-repo-count::
129 Specifies the number of entries to list per page on therepository 158 Specifies the number of entries to list per page on therepository
@@ -131,3 +160,3 @@ max-repo-count
131 160
132max-repodesc-length 161max-repodesc-length::
133 Specifies the maximum number of repo description characters to display 162 Specifies the maximum number of repo description characters to display
@@ -135,3 +164,3 @@ max-repodesc-length
135 164
136max-stats 165max-stats::
137 Set the default maximum statistics period. Valid values are "week", 166 Set the default maximum statistics period. Valid values are "week",
@@ -140,3 +169,7 @@ max-stats
140 169
141module-link 170mimetype.<ext>::
171 Set the mimetype for the specified filename extension. This is used
172 by the `plain` command when returning blob content.
173
174module-link::
142 Text which will be used as the formatstring for a hyperlink when a 175 Text which will be used as the formatstring for a hyperlink when a
@@ -146,3 +179,3 @@ module-link
146 179
147nocache 180nocache::
148 If set to the value "1" caching will be disabled. This settings is 181 If set to the value "1" caching will be disabled. This settings is
@@ -151,3 +184,11 @@ nocache
151 184
152renamelimit 185noplainemail::
186 If set to "1" showing full author email adresses will be disabled.
187 Default value: "0".
188
189noheader::
190 Flag which, when set to "1", will make cgit omit the standard header
191 on all pages. Default value: none. See also: "embedded".
192
193renamelimit::
153 Maximum number of files to consider when detecting renames. The value 194 Maximum number of files to consider when detecting renames. The value
@@ -156,3 +197,3 @@ renamelimit
156 197
157repo.group 198repo.group::
158 A value for the current repository group, which all repositories 199 A value for the current repository group, which all repositories
@@ -160,3 +201,3 @@ repo.group
160 201
161robots 202robots::
162 Text used as content for the "robots" meta-tag. Default value: 203 Text used as content for the "robots" meta-tag. Default value:
@@ -164,3 +205,3 @@ robots
164 205
165root-desc 206root-desc::
166 Text printed below the heading on the repository index page. Default 207 Text printed below the heading on the repository index page. Default
@@ -168,3 +209,3 @@ root-desc
168 209
169root-readme: 210root-readme::
170 The content of the file specified with this option will be included 211 The content of the file specified with this option will be included
@@ -173,3 +214,3 @@ root-readme:
173 214
174root-title 215root-title::
175 Text printed as heading on the repository index page. Default value: 216 Text printed as heading on the repository index page. Default value:
@@ -177,3 +218,3 @@ root-title
177 218
178snapshots 219snapshots::
179 Text which specifies the default (and allowed) set of snapshot formats 220 Text which specifies the default (and allowed) set of snapshot formats
@@ -187,3 +228,11 @@ snapshots
187 228
188summary-branches 229source-filter::
230 Specifies a command which will be invoked to format plaintext blobs
231 in the tree view. The command will get the blob content on its STDIN
232 and the name of the blob as its only command line argument. The STDOUT
233 from the command will be included verbatim as the blob contents, i.e.
234 this can be used to implement e.g. syntax highlighting. Default value:
235 none.
236
237summary-branches::
189 Specifies the number of branches to display in the repository "summary" 238 Specifies the number of branches to display in the repository "summary"
@@ -191,3 +240,3 @@ summary-branches
191 240
192summary-log 241summary-log::
193 Specifies the number of log entries to display in the repository 242 Specifies the number of log entries to display in the repository
@@ -195,3 +244,3 @@ summary-log
195 244
196summary-tags 245summary-tags::
197 Specifies the number of tags to display in the repository "summary" 246 Specifies the number of tags to display in the repository "summary"
@@ -199,3 +248,3 @@ summary-tags
199 248
200virtual-root 249virtual-root::
201 Url which, if specified, will be used as root for all cgit links. It 250 Url which, if specified, will be used as root for all cgit links. It
@@ -209,3 +258,6 @@ REPOSITORY SETTINGS
209------------------- 258-------------------
210repo.clone-url 259repo.about-filter::
260 Override the default about-filter. Default value: <about-filter>.
261
262repo.clone-url::
211 A list of space-separated urls which can be used to clone this repo. 263 A list of space-separated urls which can be used to clone this repo.
@@ -213,3 +265,6 @@ repo.clone-url
213 265
214repo.defbranch 266repo.commit-filter::
267 Override the default commit-filter. Default value: <commit-filter>.
268
269repo.defbranch::
215 The name of the default branch for this repository. If no such branch 270 The name of the default branch for this repository. If no such branch
@@ -218,6 +273,6 @@ repo.defbranch
218 273
219repo.desc 274repo.desc::
220 The value to show as repository description. Default value: none. 275 The value to show as repository description. Default value: none.
221 276
222repo.enable-log-filecount 277repo.enable-log-filecount::
223 A flag which can be used to disable the global setting 278 A flag which can be used to disable the global setting
@@ -225,3 +280,3 @@ repo.enable-log-filecount
225 280
226repo.enable-log-linecount 281repo.enable-log-linecount::
227 A flag which can be used to disable the global setting 282 A flag which can be used to disable the global setting
@@ -229,3 +284,3 @@ repo.enable-log-linecount
229 284
230repo.max-stats 285repo.max-stats::
231 Override the default maximum statistics period. Valid values are equal 286 Override the default maximum statistics period. Valid values are equal
@@ -234,6 +289,6 @@ repo.max-stats
234 289
235repo.name 290repo.name::
236 The value to show as repository name. Default value: <repo.url>. 291 The value to show as repository name. Default value: <repo.url>.
237 292
238repo.owner 293repo.owner::
239 A value used to identify the owner of the repository. Default value: 294 A value used to identify the owner of the repository. Default value:
@@ -241,3 +296,3 @@ repo.owner
241 296
242repo.path 297repo.path::
243 An absolute path to the repository directory. For non-bare repositories 298 An absolute path to the repository directory. For non-bare repositories
@@ -245,3 +300,3 @@ repo.path
245 300
246repo.readme 301repo.readme::
247 A path (relative to <repo.path>) which specifies a file to include 302 A path (relative to <repo.path>) which specifies a file to include
@@ -249,3 +304,3 @@ repo.readme
249 304
250repo.snapshots 305repo.snapshots::
251 A mask of allowed snapshot-formats for this repo, restricted by the 306 A mask of allowed snapshot-formats for this repo, restricted by the
@@ -253,3 +308,6 @@ repo.snapshots
253 308
254repo.url 309repo.source-filter::
310 Override the default source-filter. Default value: <source-filter>.
311
312repo.url::
255 The relative url used to access the repository. This must be the first 313 The relative url used to access the repository. This must be the first
@@ -261,2 +319,3 @@ EXAMPLE CGITRC FILE
261 319
320....
262# Enable caching of up to 1000 output entriess 321# Enable caching of up to 1000 output entriess
@@ -313,2 +372,15 @@ snapshots=tar.gz tar.bz2 zip
313## 372##
373## List of common mimetypes
374##
375
376mimetype.git=image/git
377mimetype.html=text/html
378mimetype.jpg=image/jpeg
379mimetype.jpeg=image/jpeg
380mimetype.pdf=application/pdf
381mimetype.png=image/png
382mimetype.svg=image/svg+xml
383
384
385##
314## List of repositories. 386## List of repositories.
@@ -370,2 +442,3 @@ repo.enable-log-linecount=0
370repo.max-stats=month 442repo.max-stats=month
443....
371 444
diff --git a/cmd.c b/cmd.c
index cf97da7..766f903 100644
--- a/cmd.c
+++ b/cmd.c
@@ -41,3 +41,3 @@ static void about_fn(struct cgit_context *ctx)
41 if (ctx->repo) 41 if (ctx->repo)
42 cgit_print_repo_readme(); 42 cgit_print_repo_readme(ctx->qry.path);
43 else 43 else
diff --git a/filters/commit-links.sh b/filters/commit-links.sh
new file mode 100755
index 0000000..165a533
--- a/dev/null
+++ b/filters/commit-links.sh
@@ -0,0 +1,12 @@
1#!/bin/sh
2# This script can be used to generate links in commit messages - the first
3# sed expression generates links to commits referenced by their SHA1, while
4# the second expression generates links to a fictional bugtracker.
5#
6# To use this script, refer to this file with either the commit-filter or the
7# repo.commit-filter options in cgitrc.
8
9sed -re '
10s|\b([0-9a-fA-F]{8,40})\b|<a href="./?id=\1">\1</a>|g
11s| #([0-9]+)\b|<a href="http://bugs.example.com/?bug=\1">#\1</a>|g
12'
diff --git a/filters/syntax-highlighting.sh b/filters/syntax-highlighting.sh
new file mode 100755
index 0000000..999ad0c
--- a/dev/null
+++ b/filters/syntax-highlighting.sh
@@ -0,0 +1,39 @@
1#!/bin/sh
2# This script can be used to implement syntax highlighting in the cgit
3# tree-view by refering to this file with the source-filter or repo.source-
4# filter options in cgitrc.
5#
6# Note: the highlight command (http://www.andre-simon.de/) uses css for syntax
7# highlighting, so you'll probably want something like the following included
8# in your css file (generated by highlight 2.4.8 and adapted for cgit):
9#
10# table.blob .num { color:#2928ff; }
11# table.blob .esc { color:#ff00ff; }
12# table.blob .str { color:#ff0000; }
13# table.blob .dstr { color:#818100; }
14# table.blob .slc { color:#838183; font-style:italic; }
15# table.blob .com { color:#838183; font-style:italic; }
16# table.blob .dir { color:#008200; }
17# table.blob .sym { color:#000000; }
18# table.blob .kwa { color:#000000; font-weight:bold; }
19# table.blob .kwb { color:#830000; }
20# table.blob .kwc { color:#000000; font-weight:bold; }
21# table.blob .kwd { color:#010181; }
22
23case "$1" in
24 *.c)
25 highlight -f -I -X -S c
26 ;;
27 *.h)
28 highlight -f -I -X -S c
29 ;;
30 *.sh)
31 highlight -f -I -X -S sh
32 ;;
33 *.css)
34 highlight -f -I -X -S css
35 ;;
36 *)
37 highlight -f -I -X -S txt
38 ;;
39esac
diff --git a/git b/git
Subproject 5c415311f743ccb11a50f350ff1c385778f049d Subproject e276f018f2c1f0fc962fbe44a36708d1cdebada
diff --git a/shared.c b/shared.c
index cce0af4..911a55a 100644
--- a/shared.c
+++ b/shared.c
@@ -64,2 +64,5 @@ struct cgit_repo *cgit_add_repo(const char *url)
64 ret->mtime = -1; 64 ret->mtime = -1;
65 ret->about_filter = ctx.cfg.about_filter;
66 ret->commit_filter = ctx.cfg.commit_filter;
67 ret->source_filter = ctx.cfg.source_filter;
65 return ret; 68 return ret;
@@ -357 +360,36 @@ int cgit_parse_snapshots_mask(const char *str)
357} 360}
361
362int cgit_open_filter(struct cgit_filter *filter)
363{
364
365 filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
366 "Unable to duplicate STDOUT");
367 chk_zero(pipe(filter->pipe_fh), "Unable to create pipe to subprocess");
368 filter->pid = chk_non_negative(fork(), "Unable to create subprocess");
369 if (filter->pid == 0) {
370 close(filter->pipe_fh[1]);
371 chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO),
372 "Unable to use pipe as STDIN");
373 execvp(filter->cmd, filter->argv);
374 die("Unable to exec subprocess %s: %s (%d)", filter->cmd,
375 strerror(errno), errno);
376 }
377 close(filter->pipe_fh[0]);
378 chk_non_negative(dup2(filter->pipe_fh[1], STDOUT_FILENO),
379 "Unable to use pipe as STDOUT");
380 close(filter->pipe_fh[1]);
381 return 0;
382}
383
384int cgit_close_filter(struct cgit_filter *filter)
385{
386 chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO),
387 "Unable to restore STDOUT");
388 close(filter->old_stdout);
389 if (filter->pid < 0)
390 return 0;
391 waitpid(filter->pid, &filter->exitstatus, 0);
392 if (WIFEXITED(filter->exitstatus) && !WEXITSTATUS(filter->exitstatus))
393 return 0;
394 die("Subprocess %s exited abnormally", filter->cmd);
395}
diff --git a/ui-atom.c b/ui-atom.c
index a6ea3ee..808b2d0 100644
--- a/ui-atom.c
+++ b/ui-atom.c
@@ -34,3 +34,3 @@ void add_entry(struct commit *commit, char *host)
34 } 34 }
35 if (info->author_email) { 35 if (info->author_email && !ctx.cfg.noplainemail) {
36 mail = xstrdup(info->author_email); 36 mail = xstrdup(info->author_email);
@@ -54,3 +54,4 @@ void add_entry(struct commit *commit, char *host)
54 if (host) { 54 if (host) {
55 html("<link rel='alternate' type='text/html' href='http://"); 55 html("<link rel='alternate' type='text/html' href='");
56 html(cgit_httpscheme());
56 html_attr(host); 57 html_attr(host);
@@ -115,3 +116,4 @@ void cgit_print_atom(char *tip, char *path, int max_count)
115 if (host) { 116 if (host) {
116 html("<link rel='alternate' type='text/html' href='http://"); 117 html("<link rel='alternate' type='text/html' href='");
118 html(cgit_httpscheme());
117 html_attr(host); 119 html_attr(host);
diff --git a/ui-blob.c b/ui-blob.c
index 3cda03d..2ccd31d 100644
--- a/ui-blob.c
+++ b/ui-blob.c
@@ -29,3 +29,3 @@ void cgit_print_blob(const char *hex, char *path, const char *head)
29 enum object_type type; 29 enum object_type type;
30 unsigned char *buf; 30 char *buf;
31 unsigned long size; 31 unsigned long size;
@@ -69,2 +69,8 @@ void cgit_print_blob(const char *hex, char *path, const char *head)
69 ctx.page.mimetype = ctx.qry.mimetype; 69 ctx.page.mimetype = ctx.qry.mimetype;
70 if (!ctx.page.mimetype) {
71 if (buffer_is_binary(buf, size))
72 ctx.page.mimetype = "application/octet-stream";
73 else
74 ctx.page.mimetype = "text/plain";
75 }
70 ctx.page.filename = path; 76 ctx.page.filename = path;
diff --git a/ui-commit.c b/ui-commit.c
index 41ce70e..d6b73ee 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -42,4 +42,6 @@ void cgit_print_commit(char *hex)
42 html_txt(info->author); 42 html_txt(info->author);
43 if (!ctx.cfg.noplainemail) {
43 html(" "); 44 html(" ");
44 html_txt(info->author_email); 45 html_txt(info->author_email);
46 }
45 html("</td><td class='right'>"); 47 html("</td><td class='right'>");
@@ -49,4 +51,6 @@ void cgit_print_commit(char *hex)
49 html_txt(info->committer); 51 html_txt(info->committer);
52 if (!ctx.cfg.noplainemail) {
50 html(" "); 53 html(" ");
51 html_txt(info->committer_email); 54 html_txt(info->committer_email);
55 }
52 html("</td><td class='right'>"); 56 html("</td><td class='right'>");
@@ -91,3 +95,7 @@ void cgit_print_commit(char *hex)
91 html("<div class='commit-subject'>"); 95 html("<div class='commit-subject'>");
96 if (ctx.repo->commit_filter)
97 cgit_open_filter(ctx.repo->commit_filter);
92 html_txt(info->subject); 98 html_txt(info->subject);
99 if (ctx.repo->commit_filter)
100 cgit_close_filter(ctx.repo->commit_filter);
93 show_commit_decorations(commit); 101 show_commit_decorations(commit);
@@ -95,3 +103,7 @@ void cgit_print_commit(char *hex)
95 html("<div class='commit-msg'>"); 103 html("<div class='commit-msg'>");
104 if (ctx.repo->commit_filter)
105 cgit_open_filter(ctx.repo->commit_filter);
96 html_txt(info->msg); 106 html_txt(info->msg);
107 if (ctx.repo->commit_filter)
108 cgit_close_filter(ctx.repo->commit_filter);
97 html("</div>"); 109 html("</div>");
diff --git a/ui-log.c b/ui-log.c
index ba2ab03..0b37785 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -55,2 +55,6 @@ void show_commit_decorations(struct commit *commit)
55 } 55 }
56 else if (!prefixcmp(deco->name, "refs/tags/")) {
57 strncpy(buf, deco->name + 10, sizeof(buf) - 1);
58 cgit_tag_link(buf, NULL, "tag-deco", ctx.qry.head, buf);
59 }
56 else if (!prefixcmp(deco->name, "refs/remotes/")) { 60 else if (!prefixcmp(deco->name, "refs/remotes/")) {
diff --git a/ui-patch.c b/ui-patch.c
index 5d665d3..2a8f7a5 100644
--- a/ui-patch.c
+++ b/ui-patch.c
@@ -110,3 +110,7 @@ void cgit_print_patch(char *hex)
110 htmlf("From %s Mon Sep 17 00:00:00 2001\n", sha1_to_hex(sha1)); 110 htmlf("From %s Mon Sep 17 00:00:00 2001\n", sha1_to_hex(sha1));
111 htmlf("From: %s %s\n", info->author, info->author_email); 111 htmlf("From: %s", info->author);
112 if (!ctx.cfg.noplainemail) {
113 htmlf(" %s", info->author_email);
114 }
115 html("\n");
112 html("Date: "); 116 html("Date: ");
diff --git a/ui-plain.c b/ui-plain.c
index 5addd9e..27c6dae 100644
--- a/ui-plain.c
+++ b/ui-plain.c
@@ -19,4 +19,5 @@ static void print_object(const unsigned char *sha1, const char *path)
19 enum object_type type; 19 enum object_type type;
20 char *buf; 20 char *buf, *ext;
21 unsigned long size; 21 unsigned long size;
22 struct string_list_item *mime;
22 23
@@ -33,5 +34,18 @@ static void print_object(const unsigned char *sha1, const char *path)
33 } 34 }
35 ctx.page.mimetype = NULL;
36 ext = strrchr(path, '.');
37 if (ext && *(++ext)) {
38 mime = string_list_lookup(ext, &ctx.cfg.mimetypes);
39 if (mime)
40 ctx.page.mimetype = (char *)mime->util;
41 }
42 if (!ctx.page.mimetype) {
43 if (buffer_is_binary(buf, size))
44 ctx.page.mimetype = "application/octet-stream";
45 else
34 ctx.page.mimetype = "text/plain"; 46 ctx.page.mimetype = "text/plain";
47 }
35 ctx.page.filename = fmt("%s", path); 48 ctx.page.filename = fmt("%s", path);
36 ctx.page.size = size; 49 ctx.page.size = size;
50 ctx.page.etag = sha1_to_hex(sha1);
37 cgit_print_http_headers(&ctx); 51 cgit_print_http_headers(&ctx);
diff --git a/ui-refs.c b/ui-refs.c
index 25da00a..d3b4f6e 100644
--- a/ui-refs.c
+++ b/ui-refs.c
@@ -48,4 +48,15 @@ static int cmp_tag_age(const void *a, const void *b)
48 struct refinfo *r2 = *(struct refinfo **)b; 48 struct refinfo *r2 = *(struct refinfo **)b;
49 int r1date, r2date;
49 50
50 return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date); 51 if (r1->object->type != OBJ_COMMIT)
52 r1date = r1->tag->tagger_date;
53 else
54 r1date = r1->commit->committer_date;
55
56 if (r2->object->type != OBJ_COMMIT)
57 r2date = r2->tag->tagger_date;
58 else
59 r2date = r2->commit->committer_date;
60
61 return cmp_age(r1date, r2date);
51} 62}
@@ -147,2 +158,8 @@ static int print_tag(struct refinfo *ref)
147 cgit_object_link(ref->object); 158 cgit_object_link(ref->object);
159 html("</td><td>");
160 if (ref->object->type == OBJ_COMMIT)
161 html(ref->commit->author);
162 html("</td><td colspan='2'>");
163 if (ref->object->type == OBJ_COMMIT)
164 cgit_print_age(ref->commit->commit->date, -1, NULL);
148 html("</td></tr>\n"); 165 html("</td></tr>\n");
diff --git a/ui-repolist.c b/ui-repolist.c
index 2c13d50..25f076f 100644
--- a/ui-repolist.c
+++ b/ui-repolist.c
@@ -275,4 +275,9 @@ void cgit_print_site_readme()
275{ 275{
276 if (ctx.cfg.root_readme) 276 if (!ctx.cfg.root_readme)
277 return;
278 if (ctx.cfg.about_filter)
279 cgit_open_filter(ctx.cfg.about_filter);
277 html_include(ctx.cfg.root_readme); 280 html_include(ctx.cfg.root_readme);
281 if (ctx.cfg.about_filter)
282 cgit_close_filter(ctx.cfg.about_filter);
278} 283}
diff --git a/ui-shared.c b/ui-shared.c
index de77bbf..cf06511 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -36,20 +36,19 @@ void cgit_print_error(char *msg)
36 36
37char *cgit_hosturl() 37char *cgit_httpscheme()
38{ 38{
39 char *host, *port; 39 if (ctx.env.https && !strcmp(ctx.env.https, "on"))
40 40 return "https://";
41 host = getenv("HTTP_HOST");
42 if (host) {
43 host = xstrdup(host);
44 } else {
45 host = getenv("SERVER_NAME");
46 if (!host)
47 return NULL;
48 port = getenv("SERVER_PORT");
49 if (port && atoi(port) != 80)
50 host = xstrdup(fmt("%s:%d", host, atoi(port)));
51 else 41 else
52 host = xstrdup(host); 42 return "http://";
53 } 43 }
54 return host; 44
45char *cgit_hosturl()
46{
47 if (ctx.env.http_host)
48 return ctx.env.http_host;
49 if (!ctx.env.server_name)
50 return NULL;
51 if (!ctx.env.server_port || atoi(ctx.env.server_port) == 80)
52 return ctx.env.server_name;
53 return xstrdup(fmt("%s:%s", ctx.env.server_name, ctx.env.server_port));
55} 54}
@@ -458,2 +457,7 @@ void cgit_print_http_headers(struct cgit_context *ctx)
458{ 457{
458 if (ctx->env.no_http && !strcmp(ctx->env.no_http, "1"))
459 return;
460
461 if (ctx->page.status)
462 htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg);
459 if (ctx->page.mimetype && ctx->page.charset) 463 if (ctx->page.mimetype && ctx->page.charset)
@@ -470,3 +474,7 @@ void cgit_print_http_headers(struct cgit_context *ctx)
470 htmlf("Expires: %s\n", http_date(ctx->page.expires)); 474 htmlf("Expires: %s\n", http_date(ctx->page.expires));
475 if (ctx->page.etag)
476 htmlf("ETag: \"%s\"\n", ctx->page.etag);
471 html("\n"); 477 html("\n");
478 if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD"))
479 exit(0);
472} 480}
@@ -475,2 +483,8 @@ void cgit_print_docstart(struct cgit_context *ctx)
475{ 483{
484 if (ctx->cfg.embedded) {
485 if (ctx->cfg.header)
486 html_include(ctx->cfg.header);
487 return;
488 }
489
476 char *host = cgit_hosturl(); 490 char *host = cgit_hosturl();
@@ -494,3 +508,4 @@ void cgit_print_docstart(struct cgit_context *ctx)
494 if (host && ctx->repo) { 508 if (host && ctx->repo) {
495 html("<link rel='alternate' title='Atom feed' href='http://"); 509 html("<link rel='alternate' title='Atom feed' href='");
510 html(cgit_httpscheme());
496 html_attr(cgit_hosturl()); 511 html_attr(cgit_hosturl());
@@ -498,4 +513,6 @@ void cgit_print_docstart(struct cgit_context *ctx)
498 fmt("h=%s", ctx->qry.head))); 513 fmt("h=%s", ctx->qry.head)));
499 html("' type='application/atom+xml'/>"); 514 html("' type='application/atom+xml'/>\n");
500 } 515 }
516 if (ctx->cfg.head_include)
517 html_include(ctx->cfg.head_include);
501 html("</head>\n"); 518 html("</head>\n");
@@ -508,3 +525,9 @@ void cgit_print_docend()
508{ 525{
509 html("</div>"); 526 html("</div> <!-- class=content -->\n");
527 if (ctx.cfg.embedded) {
528 html("</div> <!-- id=cgit -->\n");
529 if (ctx.cfg.footer)
530 html_include(ctx.cfg.footer);
531 return;
532 }
510 if (ctx.cfg.footer) 533 if (ctx.cfg.footer)
@@ -517,2 +540,3 @@ void cgit_print_docend()
517 } 540 }
541 html("</div> <!-- id=cgit -->\n");
518 html("</body>\n</html>\n"); 542 html("</body>\n</html>\n");
@@ -604,9 +628,4 @@ char *hc(struct cgit_cmd *cmd, const char *page)
604 628
605void cgit_print_pageheader(struct cgit_context *ctx) 629static void print_header(struct cgit_context *ctx)
606{ 630{
607 struct cgit_cmd *cmd = cgit_get_cmd(ctx);
608
609 if (!cmd && ctx->repo)
610 fallback_cmd = "summary";
611
612 html("<table id='header'>\n"); 631 html("<table id='header'>\n");
@@ -651,2 +670,14 @@ void cgit_print_pageheader(struct cgit_context *ctx)
651 html("</td></tr></table>\n"); 670 html("</td></tr></table>\n");
671}
672
673void cgit_print_pageheader(struct cgit_context *ctx)
674{
675 struct cgit_cmd *cmd = cgit_get_cmd(ctx);
676
677 if (!cmd && ctx->repo)
678 fallback_cmd = "summary";
679
680 html("<div id='cgit'>");
681 if (!ctx->cfg.noheader)
682 print_header(ctx);
652 683
diff --git a/ui-shared.h b/ui-shared.h
index 5a3821f..bff4826 100644
--- a/ui-shared.h
+++ b/ui-shared.h
@@ -3,2 +3,3 @@
3 3
4extern char *cgit_httpscheme();
4extern char *cgit_hosturl(); 5extern char *cgit_hosturl();
diff --git a/ui-snapshot.c b/ui-snapshot.c
index 5372f5d..4136b3e 100644
--- a/ui-snapshot.c
+++ b/ui-snapshot.c
@@ -14,33 +14,12 @@ static int write_compressed_tar_archive(struct archiver_args *args,const char *f
14{ 14{
15 int rw[2];
16 pid_t gzpid;
17 int stdout2;
18 int status;
19 int rv; 15 int rv;
16 struct cgit_filter f;
20 17
21 stdout2 = chk_non_negative(dup(STDIN_FILENO), "Preserving STDOUT before compressing"); 18 f.cmd = xstrdup(filter);
22 chk_zero(pipe(rw), "Opening pipe from compressor subprocess"); 19 f.argv = malloc(2 * sizeof(char *));
23 gzpid = chk_non_negative(fork(), "Forking compressor subprocess"); 20 f.argv[0] = f.cmd;
24 if(gzpid==0) { 21 f.argv[1] = NULL;
25 /* child */ 22 cgit_open_filter(&f);
26 chk_zero(close(rw[1]), "Closing write end of pipe in child");
27 chk_zero(close(STDIN_FILENO), "Closing STDIN");
28 chk_non_negative(dup2(rw[0],STDIN_FILENO), "Redirecting compressor input to stdin");
29 execlp(filter,filter,NULL);
30 _exit(-1);
31 }
32 /* parent */
33 chk_zero(close(rw[0]), "Closing read end of pipe");
34 chk_non_negative(dup2(rw[1],STDOUT_FILENO), "Redirecting output to compressor");
35
36 rv = write_tar_archive(args); 23 rv = write_tar_archive(args);
37 24 cgit_close_filter(&f);
38 chk_zero(close(STDOUT_FILENO), "Closing STDOUT redirected to compressor");
39 chk_non_negative(dup2(stdout2,STDOUT_FILENO), "Restoring uncompressed STDOUT");
40 chk_zero(close(stdout2), "Closing uncompressed STDOUT");
41 chk_zero(close(rw[1]), "Closing write end of pipe in parent");
42 chk_positive(waitpid(gzpid,&status,0), "Waiting on compressor process");
43 if(! ( WIFEXITED(status) && WEXITSTATUS(status)==0 ) )
44 cgit_print_error("Failed to compress archive");
45
46 return rv; 25 return rv;
diff --git a/ui-summary.c b/ui-summary.c
index ede4a62..a2c018e 100644
--- a/ui-summary.c
+++ b/ui-summary.c
@@ -68,9 +68,25 @@ void cgit_print_summary()
68 68
69void cgit_print_repo_readme() 69void cgit_print_repo_readme(char *path)
70{ 70{
71 if (ctx.repo->readme) { 71 char *slash, *tmp;
72
73 if (!ctx.repo->readme)
74 return;
75
76 if (path) {
77 slash = strrchr(ctx.repo->readme, '/');
78 if (!slash)
79 return;
80 tmp = xmalloc(slash - ctx.repo->readme + 1 + strlen(path) + 1);
81 strncpy(tmp, ctx.repo->readme, slash - ctx.repo->readme + 1);
82 strcpy(tmp + (slash - ctx.repo->readme + 1), path);
83 } else
84 tmp = ctx.repo->readme;
72 html("<div id='summary'>"); 85 html("<div id='summary'>");
73 html_include(ctx.repo->readme); 86 if (ctx.repo->about_filter)
87 cgit_open_filter(ctx.repo->about_filter);
88 html_include(tmp);
89 if (ctx.repo->about_filter)
90 cgit_close_filter(ctx.repo->about_filter);
74 html("</div>"); 91 html("</div>");
75 } 92 }
76}
diff --git a/ui-summary.h b/ui-summary.h
index 3e13039..c01f560 100644
--- a/ui-summary.h
+++ b/ui-summary.h
@@ -4,3 +4,3 @@
4extern void cgit_print_summary(); 4extern void cgit_print_summary();
5extern void cgit_print_repo_readme(); 5extern void cgit_print_repo_readme(char *path);
6 6
diff --git a/ui-tag.c b/ui-tag.c
index 8c263ab..c2d72af 100644
--- a/ui-tag.c
+++ b/ui-tag.c
@@ -69,3 +69,3 @@ void cgit_print_tag(char *revname)
69 html_txt(info->tagger); 69 html_txt(info->tagger);
70 if (info->tagger_email) { 70 if (info->tagger_email && !ctx.cfg.noplainemail) {
71 html(" "); 71 html(" ");
diff --git a/ui-tree.c b/ui-tree.c
index 553dbaa..c608754 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -17,3 +17,3 @@ int header = 0;
17 17
18static void print_text_buffer(char *buf, unsigned long size) 18static void print_text_buffer(const char *name, char *buf, unsigned long size)
19{ 19{
@@ -24,2 +24,12 @@ static void print_text_buffer(char *buf, unsigned long size)
24 html("<table summary='blob content' class='blob'>\n"); 24 html("<table summary='blob content' class='blob'>\n");
25 if (ctx.repo->source_filter) {
26 html("<tr><td class='lines'><pre><code>");
27 ctx.repo->source_filter->argv[1] = xstrdup(name);
28 cgit_open_filter(ctx.repo->source_filter);
29 write(STDOUT_FILENO, buf, size);
30 cgit_close_filter(ctx.repo->source_filter);
31 html("</code></pre></td></tr></table>\n");
32 return;
33 }
34
25 html("<tr><td class='linenumbers'><pre>"); 35 html("<tr><td class='linenumbers'><pre>");
@@ -67,3 +77,3 @@ static void print_binary_buffer(char *buf, unsigned long size)
67 77
68static void print_object(const unsigned char *sha1, char *path) 78static void print_object(const unsigned char *sha1, char *path, const char *basename)
69{ 79{
@@ -95,3 +105,3 @@ static void print_object(const unsigned char *sha1, char *path)
95 else 105 else
96 print_text_buffer(buf, size); 106 print_text_buffer(basename, buf, size);
97} 107}
@@ -105,2 +115,3 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen,
105 char *fullpath; 115 char *fullpath;
116 char *class;
106 enum object_type type; 117 enum object_type type;
@@ -137,3 +148,8 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen,
137 } else { 148 } else {
138 cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head, 149 class = strrchr(name, '.');
150 if (class != NULL) {
151 class = fmt("ls-blob %s", class + 1);
152 } else
153 class = "ls-blob";
154 cgit_tree_link(name, NULL, class, ctx.qry.head,
139 curr_rev, fullpath); 155 curr_rev, fullpath);
@@ -215,3 +231,3 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
215 } else { 231 } else {
216 print_object(sha1, buffer); 232 print_object(sha1, buffer, pathname);
217 return 0; 233 return 0;