summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2009-08-09 11:27:21 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2009-08-09 11:41:54 (UTC)
commit537c05f138d59c1eb3ac8e2d8b0dca3a38aa5dd4 (patch) (unidiff)
tree73b1d25a96dd171c5503fae1fefc6a27a7d58683
parente1782fff8a78b7f265432603351281ad2988bb40 (diff)
downloadcgit-537c05f138d59c1eb3ac8e2d8b0dca3a38aa5dd4.zip
cgit-537c05f138d59c1eb3ac8e2d8b0dca3a38aa5dd4.tar.gz
cgit-537c05f138d59c1eb3ac8e2d8b0dca3a38aa5dd4.tar.bz2
Add 'about-filter' and 'repo.about-filter' options
These options can be used to execute a filter command on each about-page, both top-level and for each repository (repo.about-filter can be used to override the current about-filter). Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c4
-rw-r--r--cgit.h2
-rw-r--r--cgitrc.5.txt10
-rw-r--r--shared.c1
-rw-r--r--ui-repolist.c9
-rw-r--r--ui-summary.c4
6 files changed, 28 insertions, 2 deletions
diff --git a/cgit.c b/cgit.c
index b3a98c1..cb1149d 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,244 +1,248 @@
1/* cgit.c: cgi for the git scm 1/* cgit.c: cgi for the git scm
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include "cache.h" 10#include "cache.h"
11#include "cmd.h" 11#include "cmd.h"
12#include "configfile.h" 12#include "configfile.h"
13#include "html.h" 13#include "html.h"
14#include "ui-shared.h" 14#include "ui-shared.h"
15#include "ui-stats.h" 15#include "ui-stats.h"
16#include "scan-tree.h" 16#include "scan-tree.h"
17 17
18const char *cgit_version = CGIT_VERSION; 18const char *cgit_version = CGIT_VERSION;
19 19
20struct cgit_filter *new_filter(const char *cmd, int extra_args) 20struct cgit_filter *new_filter(const char *cmd, int extra_args)
21{ 21{
22 struct cgit_filter *f; 22 struct cgit_filter *f;
23 23
24 if (!cmd || !cmd[0]) 24 if (!cmd || !cmd[0])
25 return NULL; 25 return NULL;
26 26
27 f = xmalloc(sizeof(struct cgit_filter)); 27 f = xmalloc(sizeof(struct cgit_filter));
28 f->cmd = xstrdup(cmd); 28 f->cmd = xstrdup(cmd);
29 f->argv = xmalloc((2 + extra_args) * sizeof(char *)); 29 f->argv = xmalloc((2 + extra_args) * sizeof(char *));
30 f->argv[0] = f->cmd; 30 f->argv[0] = f->cmd;
31 f->argv[1] = NULL; 31 f->argv[1] = NULL;
32 return f; 32 return f;
33} 33}
34 34
35void config_cb(const char *name, const char *value) 35void config_cb(const char *name, const char *value)
36{ 36{
37 if (!strcmp(name, "root-title")) 37 if (!strcmp(name, "root-title"))
38 ctx.cfg.root_title = xstrdup(value); 38 ctx.cfg.root_title = xstrdup(value);
39 else if (!strcmp(name, "root-desc")) 39 else if (!strcmp(name, "root-desc"))
40 ctx.cfg.root_desc = xstrdup(value); 40 ctx.cfg.root_desc = xstrdup(value);
41 else if (!strcmp(name, "root-readme")) 41 else if (!strcmp(name, "root-readme"))
42 ctx.cfg.root_readme = xstrdup(value); 42 ctx.cfg.root_readme = xstrdup(value);
43 else if (!strcmp(name, "css")) 43 else if (!strcmp(name, "css"))
44 ctx.cfg.css = xstrdup(value); 44 ctx.cfg.css = xstrdup(value);
45 else if (!strcmp(name, "favicon")) 45 else if (!strcmp(name, "favicon"))
46 ctx.cfg.favicon = xstrdup(value); 46 ctx.cfg.favicon = xstrdup(value);
47 else if (!strcmp(name, "footer")) 47 else if (!strcmp(name, "footer"))
48 ctx.cfg.footer = xstrdup(value); 48 ctx.cfg.footer = xstrdup(value);
49 else if (!strcmp(name, "head-include")) 49 else if (!strcmp(name, "head-include"))
50 ctx.cfg.head_include = xstrdup(value); 50 ctx.cfg.head_include = xstrdup(value);
51 else if (!strcmp(name, "header")) 51 else if (!strcmp(name, "header"))
52 ctx.cfg.header = xstrdup(value); 52 ctx.cfg.header = xstrdup(value);
53 else if (!strcmp(name, "logo")) 53 else if (!strcmp(name, "logo"))
54 ctx.cfg.logo = xstrdup(value); 54 ctx.cfg.logo = xstrdup(value);
55 else if (!strcmp(name, "index-header")) 55 else if (!strcmp(name, "index-header"))
56 ctx.cfg.index_header = xstrdup(value); 56 ctx.cfg.index_header = xstrdup(value);
57 else if (!strcmp(name, "index-info")) 57 else if (!strcmp(name, "index-info"))
58 ctx.cfg.index_info = xstrdup(value); 58 ctx.cfg.index_info = xstrdup(value);
59 else if (!strcmp(name, "logo-link")) 59 else if (!strcmp(name, "logo-link"))
60 ctx.cfg.logo_link = xstrdup(value); 60 ctx.cfg.logo_link = xstrdup(value);
61 else if (!strcmp(name, "module-link")) 61 else if (!strcmp(name, "module-link"))
62 ctx.cfg.module_link = xstrdup(value); 62 ctx.cfg.module_link = xstrdup(value);
63 else if (!strcmp(name, "virtual-root")) { 63 else if (!strcmp(name, "virtual-root")) {
64 ctx.cfg.virtual_root = trim_end(value, '/'); 64 ctx.cfg.virtual_root = trim_end(value, '/');
65 if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) 65 if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
66 ctx.cfg.virtual_root = ""; 66 ctx.cfg.virtual_root = "";
67 } else if (!strcmp(name, "nocache")) 67 } else if (!strcmp(name, "nocache"))
68 ctx.cfg.nocache = atoi(value); 68 ctx.cfg.nocache = atoi(value);
69 else if (!strcmp(name, "noheader")) 69 else if (!strcmp(name, "noheader"))
70 ctx.cfg.noheader = atoi(value); 70 ctx.cfg.noheader = atoi(value);
71 else if (!strcmp(name, "snapshots")) 71 else if (!strcmp(name, "snapshots"))
72 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); 72 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
73 else if (!strcmp(name, "enable-index-links")) 73 else if (!strcmp(name, "enable-index-links"))
74 ctx.cfg.enable_index_links = atoi(value); 74 ctx.cfg.enable_index_links = atoi(value);
75 else if (!strcmp(name, "enable-log-filecount")) 75 else if (!strcmp(name, "enable-log-filecount"))
76 ctx.cfg.enable_log_filecount = atoi(value); 76 ctx.cfg.enable_log_filecount = atoi(value);
77 else if (!strcmp(name, "enable-log-linecount")) 77 else if (!strcmp(name, "enable-log-linecount"))
78 ctx.cfg.enable_log_linecount = atoi(value); 78 ctx.cfg.enable_log_linecount = atoi(value);
79 else if (!strcmp(name, "max-stats")) 79 else if (!strcmp(name, "max-stats"))
80 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); 80 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL);
81 else if (!strcmp(name, "cache-size")) 81 else if (!strcmp(name, "cache-size"))
82 ctx.cfg.cache_size = atoi(value); 82 ctx.cfg.cache_size = atoi(value);
83 else if (!strcmp(name, "cache-root")) 83 else if (!strcmp(name, "cache-root"))
84 ctx.cfg.cache_root = xstrdup(value); 84 ctx.cfg.cache_root = xstrdup(value);
85 else if (!strcmp(name, "cache-root-ttl")) 85 else if (!strcmp(name, "cache-root-ttl"))
86 ctx.cfg.cache_root_ttl = atoi(value); 86 ctx.cfg.cache_root_ttl = atoi(value);
87 else if (!strcmp(name, "cache-repo-ttl")) 87 else if (!strcmp(name, "cache-repo-ttl"))
88 ctx.cfg.cache_repo_ttl = atoi(value); 88 ctx.cfg.cache_repo_ttl = atoi(value);
89 else if (!strcmp(name, "cache-static-ttl")) 89 else if (!strcmp(name, "cache-static-ttl"))
90 ctx.cfg.cache_static_ttl = atoi(value); 90 ctx.cfg.cache_static_ttl = atoi(value);
91 else if (!strcmp(name, "cache-dynamic-ttl")) 91 else if (!strcmp(name, "cache-dynamic-ttl"))
92 ctx.cfg.cache_dynamic_ttl = atoi(value); 92 ctx.cfg.cache_dynamic_ttl = atoi(value);
93 else if (!strcmp(name, "about-filter"))
94 ctx.cfg.about_filter = new_filter(value, 0);
93 else if (!strcmp(name, "commit-filter")) 95 else if (!strcmp(name, "commit-filter"))
94 ctx.cfg.commit_filter = new_filter(value, 0); 96 ctx.cfg.commit_filter = new_filter(value, 0);
95 else if (!strcmp(name, "embedded")) 97 else if (!strcmp(name, "embedded"))
96 ctx.cfg.embedded = atoi(value); 98 ctx.cfg.embedded = atoi(value);
97 else if (!strcmp(name, "max-message-length")) 99 else if (!strcmp(name, "max-message-length"))
98 ctx.cfg.max_msg_len = atoi(value); 100 ctx.cfg.max_msg_len = atoi(value);
99 else if (!strcmp(name, "max-repodesc-length")) 101 else if (!strcmp(name, "max-repodesc-length"))
100 ctx.cfg.max_repodesc_len = atoi(value); 102 ctx.cfg.max_repodesc_len = atoi(value);
101 else if (!strcmp(name, "max-repo-count")) 103 else if (!strcmp(name, "max-repo-count"))
102 ctx.cfg.max_repo_count = atoi(value); 104 ctx.cfg.max_repo_count = atoi(value);
103 else if (!strcmp(name, "max-commit-count")) 105 else if (!strcmp(name, "max-commit-count"))
104 ctx.cfg.max_commit_count = atoi(value); 106 ctx.cfg.max_commit_count = atoi(value);
105 else if (!strcmp(name, "source-filter")) 107 else if (!strcmp(name, "source-filter"))
106 ctx.cfg.source_filter = new_filter(value, 1); 108 ctx.cfg.source_filter = new_filter(value, 1);
107 else if (!strcmp(name, "summary-log")) 109 else if (!strcmp(name, "summary-log"))
108 ctx.cfg.summary_log = atoi(value); 110 ctx.cfg.summary_log = atoi(value);
109 else if (!strcmp(name, "summary-branches")) 111 else if (!strcmp(name, "summary-branches"))
110 ctx.cfg.summary_branches = atoi(value); 112 ctx.cfg.summary_branches = atoi(value);
111 else if (!strcmp(name, "summary-tags")) 113 else if (!strcmp(name, "summary-tags"))
112 ctx.cfg.summary_tags = atoi(value); 114 ctx.cfg.summary_tags = atoi(value);
113 else if (!strcmp(name, "agefile")) 115 else if (!strcmp(name, "agefile"))
114 ctx.cfg.agefile = xstrdup(value); 116 ctx.cfg.agefile = xstrdup(value);
115 else if (!strcmp(name, "renamelimit")) 117 else if (!strcmp(name, "renamelimit"))
116 ctx.cfg.renamelimit = atoi(value); 118 ctx.cfg.renamelimit = atoi(value);
117 else if (!strcmp(name, "robots")) 119 else if (!strcmp(name, "robots"))
118 ctx.cfg.robots = xstrdup(value); 120 ctx.cfg.robots = xstrdup(value);
119 else if (!strcmp(name, "clone-prefix")) 121 else if (!strcmp(name, "clone-prefix"))
120 ctx.cfg.clone_prefix = xstrdup(value); 122 ctx.cfg.clone_prefix = xstrdup(value);
121 else if (!strcmp(name, "local-time")) 123 else if (!strcmp(name, "local-time"))
122 ctx.cfg.local_time = atoi(value); 124 ctx.cfg.local_time = atoi(value);
123 else if (!strcmp(name, "repo.group")) 125 else if (!strcmp(name, "repo.group"))
124 ctx.cfg.repo_group = xstrdup(value); 126 ctx.cfg.repo_group = xstrdup(value);
125 else if (!strcmp(name, "repo.url")) 127 else if (!strcmp(name, "repo.url"))
126 ctx.repo = cgit_add_repo(value); 128 ctx.repo = cgit_add_repo(value);
127 else if (!strcmp(name, "repo.name")) 129 else if (!strcmp(name, "repo.name"))
128 ctx.repo->name = xstrdup(value); 130 ctx.repo->name = xstrdup(value);
129 else if (ctx.repo && !strcmp(name, "repo.path")) 131 else if (ctx.repo && !strcmp(name, "repo.path"))
130 ctx.repo->path = trim_end(value, '/'); 132 ctx.repo->path = trim_end(value, '/');
131 else if (ctx.repo && !strcmp(name, "repo.clone-url")) 133 else if (ctx.repo && !strcmp(name, "repo.clone-url"))
132 ctx.repo->clone_url = xstrdup(value); 134 ctx.repo->clone_url = xstrdup(value);
133 else if (ctx.repo && !strcmp(name, "repo.desc")) 135 else if (ctx.repo && !strcmp(name, "repo.desc"))
134 ctx.repo->desc = xstrdup(value); 136 ctx.repo->desc = xstrdup(value);
135 else if (ctx.repo && !strcmp(name, "repo.owner")) 137 else if (ctx.repo && !strcmp(name, "repo.owner"))
136 ctx.repo->owner = xstrdup(value); 138 ctx.repo->owner = xstrdup(value);
137 else if (ctx.repo && !strcmp(name, "repo.defbranch")) 139 else if (ctx.repo && !strcmp(name, "repo.defbranch"))
138 ctx.repo->defbranch = xstrdup(value); 140 ctx.repo->defbranch = xstrdup(value);
139 else if (ctx.repo && !strcmp(name, "repo.snapshots")) 141 else if (ctx.repo && !strcmp(name, "repo.snapshots"))
140 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ 142 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
141 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) 143 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount"))
142 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 144 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
143 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) 145 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount"))
144 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 146 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
145 else if (ctx.repo && !strcmp(name, "repo.max-stats")) 147 else if (ctx.repo && !strcmp(name, "repo.max-stats"))
146 ctx.repo->max_stats = cgit_find_stats_period(value, NULL); 148 ctx.repo->max_stats = cgit_find_stats_period(value, NULL);
147 else if (ctx.repo && !strcmp(name, "repo.module-link")) 149 else if (ctx.repo && !strcmp(name, "repo.module-link"))
148 ctx.repo->module_link= xstrdup(value); 150 ctx.repo->module_link= xstrdup(value);
151 else if (ctx.repo && !strcmp(name, "repo.about-filter"))
152 ctx.repo->about_filter = new_filter(value, 0);
149 else if (ctx.repo && !strcmp(name, "repo.commit-filter")) 153 else if (ctx.repo && !strcmp(name, "repo.commit-filter"))
150 ctx.repo->commit_filter = new_filter(value, 0); 154 ctx.repo->commit_filter = new_filter(value, 0);
151 else if (ctx.repo && !strcmp(name, "repo.source-filter")) 155 else if (ctx.repo && !strcmp(name, "repo.source-filter"))
152 ctx.repo->source_filter = new_filter(value, 1); 156 ctx.repo->source_filter = new_filter(value, 1);
153 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { 157 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
154 if (*value == '/') 158 if (*value == '/')
155 ctx.repo->readme = xstrdup(value); 159 ctx.repo->readme = xstrdup(value);
156 else 160 else
157 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); 161 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value));
158 } else if (!strcmp(name, "include")) 162 } else if (!strcmp(name, "include"))
159 parse_configfile(value, config_cb); 163 parse_configfile(value, config_cb);
160} 164}
161 165
162static void querystring_cb(const char *name, const char *value) 166static void querystring_cb(const char *name, const char *value)
163{ 167{
164 if (!strcmp(name,"r")) { 168 if (!strcmp(name,"r")) {
165 ctx.qry.repo = xstrdup(value); 169 ctx.qry.repo = xstrdup(value);
166 ctx.repo = cgit_get_repoinfo(value); 170 ctx.repo = cgit_get_repoinfo(value);
167 } else if (!strcmp(name, "p")) { 171 } else if (!strcmp(name, "p")) {
168 ctx.qry.page = xstrdup(value); 172 ctx.qry.page = xstrdup(value);
169 } else if (!strcmp(name, "url")) { 173 } else if (!strcmp(name, "url")) {
170 ctx.qry.url = xstrdup(value); 174 ctx.qry.url = xstrdup(value);
171 cgit_parse_url(value); 175 cgit_parse_url(value);
172 } else if (!strcmp(name, "qt")) { 176 } else if (!strcmp(name, "qt")) {
173 ctx.qry.grep = xstrdup(value); 177 ctx.qry.grep = xstrdup(value);
174 } else if (!strcmp(name, "q")) { 178 } else if (!strcmp(name, "q")) {
175 ctx.qry.search = xstrdup(value); 179 ctx.qry.search = xstrdup(value);
176 } else if (!strcmp(name, "h")) { 180 } else if (!strcmp(name, "h")) {
177 ctx.qry.head = xstrdup(value); 181 ctx.qry.head = xstrdup(value);
178 ctx.qry.has_symref = 1; 182 ctx.qry.has_symref = 1;
179 } else if (!strcmp(name, "id")) { 183 } else if (!strcmp(name, "id")) {
180 ctx.qry.sha1 = xstrdup(value); 184 ctx.qry.sha1 = xstrdup(value);
181 ctx.qry.has_sha1 = 1; 185 ctx.qry.has_sha1 = 1;
182 } else if (!strcmp(name, "id2")) { 186 } else if (!strcmp(name, "id2")) {
183 ctx.qry.sha2 = xstrdup(value); 187 ctx.qry.sha2 = xstrdup(value);
184 ctx.qry.has_sha1 = 1; 188 ctx.qry.has_sha1 = 1;
185 } else if (!strcmp(name, "ofs")) { 189 } else if (!strcmp(name, "ofs")) {
186 ctx.qry.ofs = atoi(value); 190 ctx.qry.ofs = atoi(value);
187 } else if (!strcmp(name, "path")) { 191 } else if (!strcmp(name, "path")) {
188 ctx.qry.path = trim_end(value, '/'); 192 ctx.qry.path = trim_end(value, '/');
189 } else if (!strcmp(name, "name")) { 193 } else if (!strcmp(name, "name")) {
190 ctx.qry.name = xstrdup(value); 194 ctx.qry.name = xstrdup(value);
191 } else if (!strcmp(name, "mimetype")) { 195 } else if (!strcmp(name, "mimetype")) {
192 ctx.qry.mimetype = xstrdup(value); 196 ctx.qry.mimetype = xstrdup(value);
193 } else if (!strcmp(name, "s")){ 197 } else if (!strcmp(name, "s")){
194 ctx.qry.sort = xstrdup(value); 198 ctx.qry.sort = xstrdup(value);
195 } else if (!strcmp(name, "showmsg")) { 199 } else if (!strcmp(name, "showmsg")) {
196 ctx.qry.showmsg = atoi(value); 200 ctx.qry.showmsg = atoi(value);
197 } else if (!strcmp(name, "period")) { 201 } else if (!strcmp(name, "period")) {
198 ctx.qry.period = xstrdup(value); 202 ctx.qry.period = xstrdup(value);
199 } 203 }
200} 204}
201 205
202static void prepare_context(struct cgit_context *ctx) 206static void prepare_context(struct cgit_context *ctx)
203{ 207{
204 memset(ctx, 0, sizeof(ctx)); 208 memset(ctx, 0, sizeof(ctx));
205 ctx->cfg.agefile = "info/web/last-modified"; 209 ctx->cfg.agefile = "info/web/last-modified";
206 ctx->cfg.nocache = 0; 210 ctx->cfg.nocache = 0;
207 ctx->cfg.cache_size = 0; 211 ctx->cfg.cache_size = 0;
208 ctx->cfg.cache_dynamic_ttl = 5; 212 ctx->cfg.cache_dynamic_ttl = 5;
209 ctx->cfg.cache_max_create_time = 5; 213 ctx->cfg.cache_max_create_time = 5;
210 ctx->cfg.cache_repo_ttl = 5; 214 ctx->cfg.cache_repo_ttl = 5;
211 ctx->cfg.cache_root = CGIT_CACHE_ROOT; 215 ctx->cfg.cache_root = CGIT_CACHE_ROOT;
212 ctx->cfg.cache_root_ttl = 5; 216 ctx->cfg.cache_root_ttl = 5;
213 ctx->cfg.cache_static_ttl = -1; 217 ctx->cfg.cache_static_ttl = -1;
214 ctx->cfg.css = "/cgit.css"; 218 ctx->cfg.css = "/cgit.css";
215 ctx->cfg.logo = "/git-logo.png"; 219 ctx->cfg.logo = "/git-logo.png";
216 ctx->cfg.local_time = 0; 220 ctx->cfg.local_time = 0;
217 ctx->cfg.max_repo_count = 50; 221 ctx->cfg.max_repo_count = 50;
218 ctx->cfg.max_commit_count = 50; 222 ctx->cfg.max_commit_count = 50;
219 ctx->cfg.max_lock_attempts = 5; 223 ctx->cfg.max_lock_attempts = 5;
220 ctx->cfg.max_msg_len = 80; 224 ctx->cfg.max_msg_len = 80;
221 ctx->cfg.max_repodesc_len = 80; 225 ctx->cfg.max_repodesc_len = 80;
222 ctx->cfg.max_stats = 0; 226 ctx->cfg.max_stats = 0;
223 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 227 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
224 ctx->cfg.renamelimit = -1; 228 ctx->cfg.renamelimit = -1;
225 ctx->cfg.robots = "index, nofollow"; 229 ctx->cfg.robots = "index, nofollow";
226 ctx->cfg.root_title = "Git repository browser"; 230 ctx->cfg.root_title = "Git repository browser";
227 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 231 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
228 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 232 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
229 ctx->cfg.summary_branches = 10; 233 ctx->cfg.summary_branches = 10;
230 ctx->cfg.summary_log = 10; 234 ctx->cfg.summary_log = 10;
231 ctx->cfg.summary_tags = 10; 235 ctx->cfg.summary_tags = 10;
232 ctx->page.mimetype = "text/html"; 236 ctx->page.mimetype = "text/html";
233 ctx->page.charset = PAGE_ENCODING; 237 ctx->page.charset = PAGE_ENCODING;
234 ctx->page.filename = NULL; 238 ctx->page.filename = NULL;
235 ctx->page.size = 0; 239 ctx->page.size = 0;
236 ctx->page.modified = time(NULL); 240 ctx->page.modified = time(NULL);
237 ctx->page.expires = ctx->page.modified; 241 ctx->page.expires = ctx->page.modified;
238 ctx->page.etag = NULL; 242 ctx->page.etag = NULL;
239} 243}
240 244
241struct refmatch { 245struct refmatch {
242 char *req_ref; 246 char *req_ref;
243 char *first_ref; 247 char *first_ref;
244 int match; 248 int match;
diff --git a/cgit.h b/cgit.h
index f10ba05..b8f4850 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,268 +1,270 @@
1#ifndef CGIT_H 1#ifndef CGIT_H
2#define CGIT_H 2#define CGIT_H
3 3
4 4
5#include <git-compat-util.h> 5#include <git-compat-util.h>
6#include <cache.h> 6#include <cache.h>
7#include <grep.h> 7#include <grep.h>
8#include <object.h> 8#include <object.h>
9#include <tree.h> 9#include <tree.h>
10#include <commit.h> 10#include <commit.h>
11#include <tag.h> 11#include <tag.h>
12#include <diff.h> 12#include <diff.h>
13#include <diffcore.h> 13#include <diffcore.h>
14#include <refs.h> 14#include <refs.h>
15#include <revision.h> 15#include <revision.h>
16#include <log-tree.h> 16#include <log-tree.h>
17#include <archive.h> 17#include <archive.h>
18#include <xdiff-interface.h> 18#include <xdiff-interface.h>
19#include <xdiff/xdiff.h> 19#include <xdiff/xdiff.h>
20#include <utf8.h> 20#include <utf8.h>
21 21
22 22
23/* 23/*
24 * Dateformats used on misc. pages 24 * Dateformats used on misc. pages
25 */ 25 */
26#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S (%Z)" 26#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S (%Z)"
27#define FMT_SHORTDATE "%Y-%m-%d" 27#define FMT_SHORTDATE "%Y-%m-%d"
28#define FMT_ATOMDATE "%Y-%m-%dT%H:%M:%SZ" 28#define FMT_ATOMDATE "%Y-%m-%dT%H:%M:%SZ"
29 29
30 30
31/* 31/*
32 * Limits used for relative dates 32 * Limits used for relative dates
33 */ 33 */
34#define TM_MIN 60 34#define TM_MIN 60
35#define TM_HOUR (TM_MIN * 60) 35#define TM_HOUR (TM_MIN * 60)
36#define TM_DAY (TM_HOUR * 24) 36#define TM_DAY (TM_HOUR * 24)
37#define TM_WEEK (TM_DAY * 7) 37#define TM_WEEK (TM_DAY * 7)
38#define TM_YEAR (TM_DAY * 365) 38#define TM_YEAR (TM_DAY * 365)
39#define TM_MONTH (TM_YEAR / 12.0) 39#define TM_MONTH (TM_YEAR / 12.0)
40 40
41 41
42/* 42/*
43 * Default encoding 43 * Default encoding
44 */ 44 */
45#define PAGE_ENCODING "UTF-8" 45#define PAGE_ENCODING "UTF-8"
46 46
47typedef void (*configfn)(const char *name, const char *value); 47typedef void (*configfn)(const char *name, const char *value);
48typedef void (*filepair_fn)(struct diff_filepair *pair); 48typedef void (*filepair_fn)(struct diff_filepair *pair);
49typedef void (*linediff_fn)(char *line, int len); 49typedef void (*linediff_fn)(char *line, int len);
50 50
51struct cgit_filter { 51struct cgit_filter {
52 char *cmd; 52 char *cmd;
53 char **argv; 53 char **argv;
54 int old_stdout; 54 int old_stdout;
55 int pipe_fh[2]; 55 int pipe_fh[2];
56 int pid; 56 int pid;
57 int exitstatus; 57 int exitstatus;
58}; 58};
59 59
60struct cgit_repo { 60struct cgit_repo {
61 char *url; 61 char *url;
62 char *name; 62 char *name;
63 char *path; 63 char *path;
64 char *desc; 64 char *desc;
65 char *owner; 65 char *owner;
66 char *defbranch; 66 char *defbranch;
67 char *group; 67 char *group;
68 char *module_link; 68 char *module_link;
69 char *readme; 69 char *readme;
70 char *clone_url; 70 char *clone_url;
71 int snapshots; 71 int snapshots;
72 int enable_log_filecount; 72 int enable_log_filecount;
73 int enable_log_linecount; 73 int enable_log_linecount;
74 int max_stats; 74 int max_stats;
75 time_t mtime; 75 time_t mtime;
76 struct cgit_filter *about_filter;
76 struct cgit_filter *commit_filter; 77 struct cgit_filter *commit_filter;
77 struct cgit_filter *source_filter; 78 struct cgit_filter *source_filter;
78}; 79};
79 80
80struct cgit_repolist { 81struct cgit_repolist {
81 int length; 82 int length;
82 int count; 83 int count;
83 struct cgit_repo *repos; 84 struct cgit_repo *repos;
84}; 85};
85 86
86struct commitinfo { 87struct commitinfo {
87 struct commit *commit; 88 struct commit *commit;
88 char *author; 89 char *author;
89 char *author_email; 90 char *author_email;
90 unsigned long author_date; 91 unsigned long author_date;
91 char *committer; 92 char *committer;
92 char *committer_email; 93 char *committer_email;
93 unsigned long committer_date; 94 unsigned long committer_date;
94 char *subject; 95 char *subject;
95 char *msg; 96 char *msg;
96 char *msg_encoding; 97 char *msg_encoding;
97}; 98};
98 99
99struct taginfo { 100struct taginfo {
100 char *tagger; 101 char *tagger;
101 char *tagger_email; 102 char *tagger_email;
102 unsigned long tagger_date; 103 unsigned long tagger_date;
103 char *msg; 104 char *msg;
104}; 105};
105 106
106struct refinfo { 107struct refinfo {
107 const char *refname; 108 const char *refname;
108 struct object *object; 109 struct object *object;
109 union { 110 union {
110 struct taginfo *tag; 111 struct taginfo *tag;
111 struct commitinfo *commit; 112 struct commitinfo *commit;
112 }; 113 };
113}; 114};
114 115
115struct reflist { 116struct reflist {
116 struct refinfo **refs; 117 struct refinfo **refs;
117 int alloc; 118 int alloc;
118 int count; 119 int count;
119}; 120};
120 121
121struct cgit_query { 122struct cgit_query {
122 int has_symref; 123 int has_symref;
123 int has_sha1; 124 int has_sha1;
124 char *raw; 125 char *raw;
125 char *repo; 126 char *repo;
126 char *page; 127 char *page;
127 char *search; 128 char *search;
128 char *grep; 129 char *grep;
129 char *head; 130 char *head;
130 char *sha1; 131 char *sha1;
131 char *sha2; 132 char *sha2;
132 char *path; 133 char *path;
133 char *name; 134 char *name;
134 char *mimetype; 135 char *mimetype;
135 char *url; 136 char *url;
136 char *period; 137 char *period;
137 int ofs; 138 int ofs;
138 int nohead; 139 int nohead;
139 char *sort; 140 char *sort;
140 int showmsg; 141 int showmsg;
141}; 142};
142 143
143struct cgit_config { 144struct cgit_config {
144 char *agefile; 145 char *agefile;
145 char *cache_root; 146 char *cache_root;
146 char *clone_prefix; 147 char *clone_prefix;
147 char *css; 148 char *css;
148 char *favicon; 149 char *favicon;
149 char *footer; 150 char *footer;
150 char *head_include; 151 char *head_include;
151 char *header; 152 char *header;
152 char *index_header; 153 char *index_header;
153 char *index_info; 154 char *index_info;
154 char *logo; 155 char *logo;
155 char *logo_link; 156 char *logo_link;
156 char *module_link; 157 char *module_link;
157 char *repo_group; 158 char *repo_group;
158 char *robots; 159 char *robots;
159 char *root_title; 160 char *root_title;
160 char *root_desc; 161 char *root_desc;
161 char *root_readme; 162 char *root_readme;
162 char *script_name; 163 char *script_name;
163 char *virtual_root; 164 char *virtual_root;
164 int cache_size; 165 int cache_size;
165 int cache_dynamic_ttl; 166 int cache_dynamic_ttl;
166 int cache_max_create_time; 167 int cache_max_create_time;
167 int cache_repo_ttl; 168 int cache_repo_ttl;
168 int cache_root_ttl; 169 int cache_root_ttl;
169 int cache_static_ttl; 170 int cache_static_ttl;
170 int embedded; 171 int embedded;
171 int enable_index_links; 172 int enable_index_links;
172 int enable_log_filecount; 173 int enable_log_filecount;
173 int enable_log_linecount; 174 int enable_log_linecount;
174 int local_time; 175 int local_time;
175 int max_repo_count; 176 int max_repo_count;
176 int max_commit_count; 177 int max_commit_count;
177 int max_lock_attempts; 178 int max_lock_attempts;
178 int max_msg_len; 179 int max_msg_len;
179 int max_repodesc_len; 180 int max_repodesc_len;
180 int max_stats; 181 int max_stats;
181 int nocache; 182 int nocache;
182 int noheader; 183 int noheader;
183 int renamelimit; 184 int renamelimit;
184 int snapshots; 185 int snapshots;
185 int summary_branches; 186 int summary_branches;
186 int summary_log; 187 int summary_log;
187 int summary_tags; 188 int summary_tags;
189 struct cgit_filter *about_filter;
188 struct cgit_filter *commit_filter; 190 struct cgit_filter *commit_filter;
189 struct cgit_filter *source_filter; 191 struct cgit_filter *source_filter;
190}; 192};
191 193
192struct cgit_page { 194struct cgit_page {
193 time_t modified; 195 time_t modified;
194 time_t expires; 196 time_t expires;
195 size_t size; 197 size_t size;
196 char *mimetype; 198 char *mimetype;
197 char *charset; 199 char *charset;
198 char *filename; 200 char *filename;
199 char *etag; 201 char *etag;
200 char *title; 202 char *title;
201 int status; 203 int status;
202 char *statusmsg; 204 char *statusmsg;
203}; 205};
204 206
205struct cgit_context { 207struct cgit_context {
206 struct cgit_query qry; 208 struct cgit_query qry;
207 struct cgit_config cfg; 209 struct cgit_config cfg;
208 struct cgit_repo *repo; 210 struct cgit_repo *repo;
209 struct cgit_page page; 211 struct cgit_page page;
210}; 212};
211 213
212struct cgit_snapshot_format { 214struct cgit_snapshot_format {
213 const char *suffix; 215 const char *suffix;
214 const char *mimetype; 216 const char *mimetype;
215 write_archive_fn_t write_func; 217 write_archive_fn_t write_func;
216 int bit; 218 int bit;
217}; 219};
218 220
219extern const char *cgit_version; 221extern const char *cgit_version;
220 222
221extern struct cgit_repolist cgit_repolist; 223extern struct cgit_repolist cgit_repolist;
222extern struct cgit_context ctx; 224extern struct cgit_context ctx;
223extern const struct cgit_snapshot_format cgit_snapshot_formats[]; 225extern const struct cgit_snapshot_format cgit_snapshot_formats[];
224 226
225extern struct cgit_repo *cgit_add_repo(const char *url); 227extern struct cgit_repo *cgit_add_repo(const char *url);
226extern struct cgit_repo *cgit_get_repoinfo(const char *url); 228extern struct cgit_repo *cgit_get_repoinfo(const char *url);
227extern void cgit_repo_config_cb(const char *name, const char *value); 229extern void cgit_repo_config_cb(const char *name, const char *value);
228 230
229extern int chk_zero(int result, char *msg); 231extern int chk_zero(int result, char *msg);
230extern int chk_positive(int result, char *msg); 232extern int chk_positive(int result, char *msg);
231extern int chk_non_negative(int result, char *msg); 233extern int chk_non_negative(int result, char *msg);
232 234
233extern char *trim_end(const char *str, char c); 235extern char *trim_end(const char *str, char c);
234extern char *strlpart(char *txt, int maxlen); 236extern char *strlpart(char *txt, int maxlen);
235extern char *strrpart(char *txt, int maxlen); 237extern char *strrpart(char *txt, int maxlen);
236 238
237extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); 239extern void cgit_add_ref(struct reflist *list, struct refinfo *ref);
238extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, 240extern int cgit_refs_cb(const char *refname, const unsigned char *sha1,
239 int flags, void *cb_data); 241 int flags, void *cb_data);
240 242
241extern void *cgit_free_commitinfo(struct commitinfo *info); 243extern void *cgit_free_commitinfo(struct commitinfo *info);
242 244
243extern int cgit_diff_files(const unsigned char *old_sha1, 245extern int cgit_diff_files(const unsigned char *old_sha1,
244 const unsigned char *new_sha1, 246 const unsigned char *new_sha1,
245 unsigned long *old_size, unsigned long *new_size, 247 unsigned long *old_size, unsigned long *new_size,
246 int *binary, linediff_fn fn); 248 int *binary, linediff_fn fn);
247 249
248extern void cgit_diff_tree(const unsigned char *old_sha1, 250extern void cgit_diff_tree(const unsigned char *old_sha1,
249 const unsigned char *new_sha1, 251 const unsigned char *new_sha1,
250 filepair_fn fn, const char *prefix); 252 filepair_fn fn, const char *prefix);
251 253
252extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 254extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
253 255
254extern char *fmt(const char *format,...); 256extern char *fmt(const char *format,...);
255 257
256extern struct commitinfo *cgit_parse_commit(struct commit *commit); 258extern struct commitinfo *cgit_parse_commit(struct commit *commit);
257extern struct taginfo *cgit_parse_tag(struct tag *tag); 259extern struct taginfo *cgit_parse_tag(struct tag *tag);
258extern void cgit_parse_url(const char *url); 260extern void cgit_parse_url(const char *url);
259 261
260extern const char *cgit_repobasename(const char *reponame); 262extern const char *cgit_repobasename(const char *reponame);
261 263
262extern int cgit_parse_snapshots_mask(const char *str); 264extern int cgit_parse_snapshots_mask(const char *str);
263 265
264extern int cgit_open_filter(struct cgit_filter *filter); 266extern int cgit_open_filter(struct cgit_filter *filter);
265extern int cgit_close_filter(struct cgit_filter *filter); 267extern int cgit_close_filter(struct cgit_filter *filter);
266 268
267 269
268#endif /* CGIT_H */ 270#endif /* CGIT_H */
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index ffb3e0f..d8e4b97 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -1,114 +1,121 @@
1CGITRC(5) 1CGITRC(5)
2======== 2========
3 3
4 4
5NAME 5NAME
6---- 6----
7cgitrc - runtime configuration for cgit 7cgitrc - runtime configuration for cgit
8 8
9 9
10SYNOPSIS 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
13repositories, formatted as a line-separated list of NAME=VALUE pairs. Blank 13repositories, formatted as a line-separated list of NAME=VALUE pairs. Blank
14lines, and lines starting with '#', are ignored. 14lines, and lines starting with '#', are ignored.
15 15
16 16
17GLOBAL SETTINGS 17GLOBAL SETTINGS
18--------------- 18---------------
19about-filter::
20 Specifies a command which will be invoked to format the content of
21 about pages (both top-level and for each repository). The command will
22 get the content of the about-file on its STDIN, and the STDOUT from the
23 command will be included verbatim on the about page. Default value:
24 none.
25
19agefile:: 26agefile::
20 Specifies a path, relative to each repository path, which can be used 27 Specifies a path, relative to each repository path, which can be used
21 to specify the date and time of the youngest commit in the repository. 28 to specify the date and time of the youngest commit in the repository.
22 The first line in the file is used as input to the "parse_date" 29 The first line in the file is used as input to the "parse_date"
23 function in libgit. Recommended timestamp-format is "yyyy-mm-dd 30 function in libgit. Recommended timestamp-format is "yyyy-mm-dd
24 hh:mm:ss". Default value: "info/web/last-modified". 31 hh:mm:ss". Default value: "info/web/last-modified".
25 32
26cache-root:: 33cache-root::
27 Path used to store the cgit cache entries. Default value: 34 Path used to store the cgit cache entries. Default value:
28 "/var/cache/cgit". 35 "/var/cache/cgit".
29 36
30cache-dynamic-ttl:: 37cache-dynamic-ttl::
31 Number which specifies the time-to-live, in minutes, for the cached 38 Number which specifies the time-to-live, in minutes, for the cached
32 version of repository pages accessed without a fixed SHA1. Default 39 version of repository pages accessed without a fixed SHA1. Default
33 value: "5". 40 value: "5".
34 41
35cache-repo-ttl:: 42cache-repo-ttl::
36 Number which specifies the time-to-live, in minutes, for the cached 43 Number which specifies the time-to-live, in minutes, for the cached
37 version of the repository summary page. Default value: "5". 44 version of the repository summary page. Default value: "5".
38 45
39cache-root-ttl:: 46cache-root-ttl::
40 Number which specifies the time-to-live, in minutes, for the cached 47 Number which specifies the time-to-live, in minutes, for the cached
41 version of the repository index page. Default value: "5". 48 version of the repository index page. Default value: "5".
42 49
43cache-size:: 50cache-size::
44 The maximum number of entries in the cgit cache. Default value: "0" 51 The maximum number of entries in the cgit cache. Default value: "0"
45 (i.e. caching is disabled). 52 (i.e. caching is disabled).
46 53
47cache-static-ttl:: 54cache-static-ttl::
48 Number which specifies the time-to-live, in minutes, for the cached 55 Number which specifies the time-to-live, in minutes, for the cached
49 version of repository pages accessed with a fixed SHA1. Default value: 56 version of repository pages accessed with a fixed SHA1. Default value:
50 "5". 57 "5".
51 58
52clone-prefix:: 59clone-prefix::
53 Space-separated list of common prefixes which, when combined with a 60 Space-separated list of common prefixes which, when combined with a
54 repository url, generates valid clone urls for the repository. This 61 repository url, generates valid clone urls for the repository. This
55 setting is only used if `repo.clone-url` is unspecified. Default value: 62 setting is only used if `repo.clone-url` is unspecified. Default value:
56 none. 63 none.
57 64
58commit-filter:: 65commit-filter::
59 Specifies a command which will be invoked to format commit messages. 66 Specifies a command which will be invoked to format commit messages.
60 The command will get the message on its STDIN, and the STDOUT from the 67 The command will get the message on its STDIN, and the STDOUT from the
61 command will be included verbatim as the commit message, i.e. this can 68 command will be included verbatim as the commit message, i.e. this can
62 be used to implement bugtracker integration. Default value: none. 69 be used to implement bugtracker integration. Default value: none.
63 70
64css:: 71css::
65 Url which specifies the css document to include in all cgit pages. 72 Url which specifies the css document to include in all cgit pages.
66 Default value: "/cgit.css". 73 Default value: "/cgit.css".
67 74
68embedded:: 75embedded::
69 Flag which, when set to "1", will make cgit generate a html fragment 76 Flag which, when set to "1", will make cgit generate a html fragment
70 suitable for embedding in other html pages. Default value: none. See 77 suitable for embedding in other html pages. Default value: none. See
71 also: "noheader". 78 also: "noheader".
72 79
73enable-index-links:: 80enable-index-links::
74 Flag which, when set to "1", will make cgit generate extra links for 81 Flag which, when set to "1", will make cgit generate extra links for
75 each repo in the repository index (specifically, to the "summary", 82 each repo in the repository index (specifically, to the "summary",
76 "commit" and "tree" pages). Default value: "0". 83 "commit" and "tree" pages). Default value: "0".
77 84
78enable-log-filecount:: 85enable-log-filecount::
79 Flag which, when set to "1", will make cgit print the number of 86 Flag which, when set to "1", will make cgit print the number of
80 modified files for each commit on the repository log page. Default 87 modified files for each commit on the repository log page. Default
81 value: "0". 88 value: "0".
82 89
83enable-log-linecount:: 90enable-log-linecount::
84 Flag which, when set to "1", will make cgit print the number of added 91 Flag which, when set to "1", will make cgit print the number of added
85 and removed lines for each commit on the repository log page. Default 92 and removed lines for each commit on the repository log page. Default
86 value: "0". 93 value: "0".
87 94
88favicon:: 95favicon::
89 Url used as link to a shortcut icon for cgit. If specified, it is 96 Url used as link to a shortcut icon for cgit. If specified, it is
90 suggested to use the value "/favicon.ico" since certain browsers will 97 suggested to use the value "/favicon.ico" since certain browsers will
91 ignore other values. Default value: none. 98 ignore other values. Default value: none.
92 99
93footer:: 100footer::
94 The content of the file specified with this option will be included 101 The content of the file specified with this option will be included
95 verbatim at the bottom of all pages (i.e. it replaces the standard 102 verbatim at the bottom of all pages (i.e. it replaces the standard
96 "generated by..." message. Default value: none. 103 "generated by..." message. Default value: none.
97 104
98head-include:: 105head-include::
99 The content of the file specified with this option will be included 106 The content of the file specified with this option will be included
100 verbatim in the html HEAD section on all pages. Default value: none. 107 verbatim in the html HEAD section on all pages. Default value: none.
101 108
102header:: 109header::
103 The content of the file specified with this option will be included 110 The content of the file specified with this option will be included
104 verbatim at the top of all pages. Default value: none. 111 verbatim at the top of all pages. Default value: none.
105 112
106include:: 113include::
107 Name of a configfile to include before the rest of the current config- 114 Name of a configfile to include before the rest of the current config-
108 file is parsed. Default value: none. 115 file is parsed. Default value: none.
109 116
110index-header:: 117index-header::
111 The content of the file specified with this option will be included 118 The content of the file specified with this option will be included
112 verbatim above the repository index. This setting is deprecated, and 119 verbatim above the repository index. This setting is deprecated, and
113 will not be supported by cgit-1.0 (use root-readme instead). Default 120 will not be supported by cgit-1.0 (use root-readme instead). Default
114 value: none. 121 value: none.
@@ -141,192 +148,195 @@ max-message-length::
141 "log" view. Default value: "80". 148 "log" view. Default value: "80".
142 149
143max-repo-count:: 150max-repo-count::
144 Specifies the number of entries to list per page on therepository 151 Specifies the number of entries to list per page on therepository
145 index page. Default value: "50". 152 index page. Default value: "50".
146 153
147max-repodesc-length:: 154max-repodesc-length::
148 Specifies the maximum number of repo description characters to display 155 Specifies the maximum number of repo description characters to display
149 on the repository index page. Default value: "80". 156 on the repository index page. Default value: "80".
150 157
151max-stats:: 158max-stats::
152 Set the default maximum statistics period. Valid values are "week", 159 Set the default maximum statistics period. Valid values are "week",
153 "month", "quarter" and "year". If unspecified, statistics are 160 "month", "quarter" and "year". If unspecified, statistics are
154 disabled. Default value: none. See also: "repo.max-stats". 161 disabled. Default value: none. See also: "repo.max-stats".
155 162
156module-link:: 163module-link::
157 Text which will be used as the formatstring for a hyperlink when a 164 Text which will be used as the formatstring for a hyperlink when a
158 submodule is printed in a directory listing. The arguments for the 165 submodule is printed in a directory listing. The arguments for the
159 formatstring are the path and SHA1 of the submodule commit. Default 166 formatstring are the path and SHA1 of the submodule commit. Default
160 value: "./?repo=%s&page=commit&id=%s" 167 value: "./?repo=%s&page=commit&id=%s"
161 168
162nocache:: 169nocache::
163 If set to the value "1" caching will be disabled. This settings is 170 If set to the value "1" caching will be disabled. This settings is
164 deprecated, and will not be honored starting with cgit-1.0. Default 171 deprecated, and will not be honored starting with cgit-1.0. Default
165 value: "0". 172 value: "0".
166 173
167noheader:: 174noheader::
168 Flag which, when set to "1", will make cgit omit the standard header 175 Flag which, when set to "1", will make cgit omit the standard header
169 on all pages. Default value: none. See also: "embedded". 176 on all pages. Default value: none. See also: "embedded".
170 177
171renamelimit:: 178renamelimit::
172 Maximum number of files to consider when detecting renames. The value 179 Maximum number of files to consider when detecting renames. The value
173 "-1" uses the compiletime value in git (for further info, look at 180 "-1" uses the compiletime value in git (for further info, look at
174 `man git-diff`). Default value: "-1". 181 `man git-diff`). Default value: "-1".
175 182
176repo.group:: 183repo.group::
177 A value for the current repository group, which all repositories 184 A value for the current repository group, which all repositories
178 specified after this setting will inherit. Default value: none. 185 specified after this setting will inherit. Default value: none.
179 186
180robots:: 187robots::
181 Text used as content for the "robots" meta-tag. Default value: 188 Text used as content for the "robots" meta-tag. Default value:
182 "index, nofollow". 189 "index, nofollow".
183 190
184root-desc:: 191root-desc::
185 Text printed below the heading on the repository index page. Default 192 Text printed below the heading on the repository index page. Default
186 value: "a fast webinterface for the git dscm". 193 value: "a fast webinterface for the git dscm".
187 194
188root-readme:: 195root-readme::
189 The content of the file specified with this option will be included 196 The content of the file specified with this option will be included
190 verbatim below the "about" link on the repository index page. Default 197 verbatim below the "about" link on the repository index page. Default
191 value: none. 198 value: none.
192 199
193root-title:: 200root-title::
194 Text printed as heading on the repository index page. Default value: 201 Text printed as heading on the repository index page. Default value:
195 "Git Repository Browser". 202 "Git Repository Browser".
196 203
197snapshots:: 204snapshots::
198 Text which specifies the default (and allowed) set of snapshot formats 205 Text which specifies the default (and allowed) set of snapshot formats
199 supported by cgit. The value is a space-separated list of zero or more 206 supported by cgit. The value is a space-separated list of zero or more
200 of the following values: 207 of the following values:
201 "tar" uncompressed tar-file 208 "tar" uncompressed tar-file
202 "tar.gz"gzip-compressed tar-file 209 "tar.gz"gzip-compressed tar-file
203 "tar.bz2"bzip-compressed tar-file 210 "tar.bz2"bzip-compressed tar-file
204 "zip" zip-file 211 "zip" zip-file
205 Default value: none. 212 Default value: none.
206 213
207source-filter:: 214source-filter::
208 Specifies a command which will be invoked to format plaintext blobs 215 Specifies a command which will be invoked to format plaintext blobs
209 in the tree view. The command will get the blob content on its STDIN 216 in the tree view. The command will get the blob content on its STDIN
210 and the name of the blob as its only command line argument. The STDOUT 217 and the name of the blob as its only command line argument. The STDOUT
211 from the command will be included verbatim as the blob contents, i.e. 218 from the command will be included verbatim as the blob contents, i.e.
212 this can be used to implement e.g. syntax highlighting. Default value: 219 this can be used to implement e.g. syntax highlighting. Default value:
213 none. 220 none.
214 221
215summary-branches:: 222summary-branches::
216 Specifies the number of branches to display in the repository "summary" 223 Specifies the number of branches to display in the repository "summary"
217 view. Default value: "10". 224 view. Default value: "10".
218 225
219summary-log:: 226summary-log::
220 Specifies the number of log entries to display in the repository 227 Specifies the number of log entries to display in the repository
221 "summary" view. Default value: "10". 228 "summary" view. Default value: "10".
222 229
223summary-tags:: 230summary-tags::
224 Specifies the number of tags to display in the repository "summary" 231 Specifies the number of tags to display in the repository "summary"
225 view. Default value: "10". 232 view. Default value: "10".
226 233
227virtual-root:: 234virtual-root::
228 Url which, if specified, will be used as root for all cgit links. It 235 Url which, if specified, will be used as root for all cgit links. It
229 will also cause cgit to generate 'virtual urls', i.e. urls like 236 will also cause cgit to generate 'virtual urls', i.e. urls like
230 '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default 237 '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default
231 value: none. 238 value: none.
232 NOTE: cgit has recently learned how to use PATH_INFO to achieve the 239 NOTE: cgit has recently learned how to use PATH_INFO to achieve the
233 same kind of virtual urls, so this option will probably be deprecated. 240 same kind of virtual urls, so this option will probably be deprecated.
234 241
235REPOSITORY SETTINGS 242REPOSITORY SETTINGS
236------------------- 243-------------------
244repo.about-filter::
245 Override the default about-filter. Default value: <about-filter>.
246
237repo.clone-url:: 247repo.clone-url::
238 A list of space-separated urls which can be used to clone this repo. 248 A list of space-separated urls which can be used to clone this repo.
239 Default value: none. 249 Default value: none.
240 250
241repo.commit-filter:: 251repo.commit-filter::
242 Override the default commit-filter. Default value: <commit-filter>. 252 Override the default commit-filter. Default value: <commit-filter>.
243 253
244repo.defbranch:: 254repo.defbranch::
245 The name of the default branch for this repository. If no such branch 255 The name of the default branch for this repository. If no such branch
246 exists in the repository, the first branch name (when sorted) is used 256 exists in the repository, the first branch name (when sorted) is used
247 as default instead. Default value: "master". 257 as default instead. Default value: "master".
248 258
249repo.desc:: 259repo.desc::
250 The value to show as repository description. Default value: none. 260 The value to show as repository description. Default value: none.
251 261
252repo.enable-log-filecount:: 262repo.enable-log-filecount::
253 A flag which can be used to disable the global setting 263 A flag which can be used to disable the global setting
254 `enable-log-filecount'. Default value: none. 264 `enable-log-filecount'. Default value: none.
255 265
256repo.enable-log-linecount:: 266repo.enable-log-linecount::
257 A flag which can be used to disable the global setting 267 A flag which can be used to disable the global setting
258 `enable-log-linecount'. Default value: none. 268 `enable-log-linecount'. Default value: none.
259 269
260repo.max-stats:: 270repo.max-stats::
261 Override the default maximum statistics period. Valid values are equal 271 Override the default maximum statistics period. Valid values are equal
262 to the values specified for the global "max-stats" setting. Default 272 to the values specified for the global "max-stats" setting. Default
263 value: none. 273 value: none.
264 274
265repo.name:: 275repo.name::
266 The value to show as repository name. Default value: <repo.url>. 276 The value to show as repository name. Default value: <repo.url>.
267 277
268repo.owner:: 278repo.owner::
269 A value used to identify the owner of the repository. Default value: 279 A value used to identify the owner of the repository. Default value:
270 none. 280 none.
271 281
272repo.path:: 282repo.path::
273 An absolute path to the repository directory. For non-bare repositories 283 An absolute path to the repository directory. For non-bare repositories
274 this is the .git-directory. Default value: none. 284 this is the .git-directory. Default value: none.
275 285
276repo.readme:: 286repo.readme::
277 A path (relative to <repo.path>) which specifies a file to include 287 A path (relative to <repo.path>) which specifies a file to include
278 verbatim as the "About" page for this repo. Default value: none. 288 verbatim as the "About" page for this repo. Default value: none.
279 289
280repo.snapshots:: 290repo.snapshots::
281 A mask of allowed snapshot-formats for this repo, restricted by the 291 A mask of allowed snapshot-formats for this repo, restricted by the
282 "snapshots" global setting. Default value: <snapshots>. 292 "snapshots" global setting. Default value: <snapshots>.
283 293
284repo.source-filter:: 294repo.source-filter::
285 Override the default source-filter. Default value: <source-filter>. 295 Override the default source-filter. Default value: <source-filter>.
286 296
287repo.url:: 297repo.url::
288 The relative url used to access the repository. This must be the first 298 The relative url used to access the repository. This must be the first
289 setting specified for each repo. Default value: none. 299 setting specified for each repo. Default value: none.
290 300
291 301
292EXAMPLE CGITRC FILE 302EXAMPLE CGITRC FILE
293------------------- 303-------------------
294 304
295.... 305....
296# Enable caching of up to 1000 output entriess 306# Enable caching of up to 1000 output entriess
297cache-size=1000 307cache-size=1000
298 308
299 309
300# Specify some default clone prefixes 310# Specify some default clone prefixes
301clone-prefix=git://foobar.com ssh://foobar.com/pub/git http://foobar.com/git 311clone-prefix=git://foobar.com ssh://foobar.com/pub/git http://foobar.com/git
302 312
303# Specify the css url 313# Specify the css url
304css=/css/cgit.css 314css=/css/cgit.css
305 315
306 316
307# Show extra links for each repository on the index page 317# Show extra links for each repository on the index page
308enable-index-links=1 318enable-index-links=1
309 319
310 320
311# Show number of affected files per commit on the log pages 321# Show number of affected files per commit on the log pages
312enable-log-filecount=1 322enable-log-filecount=1
313 323
314 324
315# Show number of added/removed lines per commit on the log pages 325# Show number of added/removed lines per commit on the log pages
316enable-log-linecount=1 326enable-log-linecount=1
317 327
318 328
319# Add a cgit favicon 329# Add a cgit favicon
320favicon=/favicon.ico 330favicon=/favicon.ico
321 331
322 332
323# Use a custom logo 333# Use a custom logo
324logo=/img/mylogo.png 334logo=/img/mylogo.png
325 335
326 336
327# Enable statistics per week, month and quarter 337# Enable statistics per week, month and quarter
328max-stats=quarter 338max-stats=quarter
329 339
330 340
331# Set the title and heading of the repository index page 341# Set the title and heading of the repository index page
332root-title=foobar.com git repositories 342root-title=foobar.com git repositories
diff --git a/shared.c b/shared.c
index 783604b..911a55a 100644
--- a/shared.c
+++ b/shared.c
@@ -1,160 +1,161 @@
1/* shared.c: global vars + some callback functions 1/* shared.c: global vars + some callback functions
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10 10
11struct cgit_repolist cgit_repolist; 11struct cgit_repolist cgit_repolist;
12struct cgit_context ctx; 12struct cgit_context ctx;
13int cgit_cmd; 13int cgit_cmd;
14 14
15int chk_zero(int result, char *msg) 15int chk_zero(int result, char *msg)
16{ 16{
17 if (result != 0) 17 if (result != 0)
18 die("%s: %s", msg, strerror(errno)); 18 die("%s: %s", msg, strerror(errno));
19 return result; 19 return result;
20} 20}
21 21
22int chk_positive(int result, char *msg) 22int chk_positive(int result, char *msg)
23{ 23{
24 if (result <= 0) 24 if (result <= 0)
25 die("%s: %s", msg, strerror(errno)); 25 die("%s: %s", msg, strerror(errno));
26 return result; 26 return result;
27} 27}
28 28
29int chk_non_negative(int result, char *msg) 29int chk_non_negative(int result, char *msg)
30{ 30{
31 if (result < 0) 31 if (result < 0)
32 die("%s: %s",msg, strerror(errno)); 32 die("%s: %s",msg, strerror(errno));
33 return result; 33 return result;
34} 34}
35 35
36struct cgit_repo *cgit_add_repo(const char *url) 36struct cgit_repo *cgit_add_repo(const char *url)
37{ 37{
38 struct cgit_repo *ret; 38 struct cgit_repo *ret;
39 39
40 if (++cgit_repolist.count > cgit_repolist.length) { 40 if (++cgit_repolist.count > cgit_repolist.length) {
41 if (cgit_repolist.length == 0) 41 if (cgit_repolist.length == 0)
42 cgit_repolist.length = 8; 42 cgit_repolist.length = 8;
43 else 43 else
44 cgit_repolist.length *= 2; 44 cgit_repolist.length *= 2;
45 cgit_repolist.repos = xrealloc(cgit_repolist.repos, 45 cgit_repolist.repos = xrealloc(cgit_repolist.repos,
46 cgit_repolist.length * 46 cgit_repolist.length *
47 sizeof(struct cgit_repo)); 47 sizeof(struct cgit_repo));
48 } 48 }
49 49
50 ret = &cgit_repolist.repos[cgit_repolist.count-1]; 50 ret = &cgit_repolist.repos[cgit_repolist.count-1];
51 ret->url = trim_end(url, '/'); 51 ret->url = trim_end(url, '/');
52 ret->name = ret->url; 52 ret->name = ret->url;
53 ret->path = NULL; 53 ret->path = NULL;
54 ret->desc = "[no description]"; 54 ret->desc = "[no description]";
55 ret->owner = NULL; 55 ret->owner = NULL;
56 ret->group = ctx.cfg.repo_group; 56 ret->group = ctx.cfg.repo_group;
57 ret->defbranch = "master"; 57 ret->defbranch = "master";
58 ret->snapshots = ctx.cfg.snapshots; 58 ret->snapshots = ctx.cfg.snapshots;
59 ret->enable_log_filecount = ctx.cfg.enable_log_filecount; 59 ret->enable_log_filecount = ctx.cfg.enable_log_filecount;
60 ret->enable_log_linecount = ctx.cfg.enable_log_linecount; 60 ret->enable_log_linecount = ctx.cfg.enable_log_linecount;
61 ret->max_stats = ctx.cfg.max_stats; 61 ret->max_stats = ctx.cfg.max_stats;
62 ret->module_link = ctx.cfg.module_link; 62 ret->module_link = ctx.cfg.module_link;
63 ret->readme = NULL; 63 ret->readme = NULL;
64 ret->mtime = -1; 64 ret->mtime = -1;
65 ret->about_filter = ctx.cfg.about_filter;
65 ret->commit_filter = ctx.cfg.commit_filter; 66 ret->commit_filter = ctx.cfg.commit_filter;
66 ret->source_filter = ctx.cfg.source_filter; 67 ret->source_filter = ctx.cfg.source_filter;
67 return ret; 68 return ret;
68} 69}
69 70
70struct cgit_repo *cgit_get_repoinfo(const char *url) 71struct cgit_repo *cgit_get_repoinfo(const char *url)
71{ 72{
72 int i; 73 int i;
73 struct cgit_repo *repo; 74 struct cgit_repo *repo;
74 75
75 for (i=0; i<cgit_repolist.count; i++) { 76 for (i=0; i<cgit_repolist.count; i++) {
76 repo = &cgit_repolist.repos[i]; 77 repo = &cgit_repolist.repos[i];
77 if (!strcmp(repo->url, url)) 78 if (!strcmp(repo->url, url))
78 return repo; 79 return repo;
79 } 80 }
80 return NULL; 81 return NULL;
81} 82}
82 83
83void *cgit_free_commitinfo(struct commitinfo *info) 84void *cgit_free_commitinfo(struct commitinfo *info)
84{ 85{
85 free(info->author); 86 free(info->author);
86 free(info->author_email); 87 free(info->author_email);
87 free(info->committer); 88 free(info->committer);
88 free(info->committer_email); 89 free(info->committer_email);
89 free(info->subject); 90 free(info->subject);
90 free(info->msg); 91 free(info->msg);
91 free(info->msg_encoding); 92 free(info->msg_encoding);
92 free(info); 93 free(info);
93 return NULL; 94 return NULL;
94} 95}
95 96
96char *trim_end(const char *str, char c) 97char *trim_end(const char *str, char c)
97{ 98{
98 int len; 99 int len;
99 char *s, *t; 100 char *s, *t;
100 101
101 if (str == NULL) 102 if (str == NULL)
102 return NULL; 103 return NULL;
103 t = (char *)str; 104 t = (char *)str;
104 len = strlen(t); 105 len = strlen(t);
105 while(len > 0 && t[len - 1] == c) 106 while(len > 0 && t[len - 1] == c)
106 len--; 107 len--;
107 108
108 if (len == 0) 109 if (len == 0)
109 return NULL; 110 return NULL;
110 111
111 c = t[len]; 112 c = t[len];
112 t[len] = '\0'; 113 t[len] = '\0';
113 s = xstrdup(t); 114 s = xstrdup(t);
114 t[len] = c; 115 t[len] = c;
115 return s; 116 return s;
116} 117}
117 118
118char *strlpart(char *txt, int maxlen) 119char *strlpart(char *txt, int maxlen)
119{ 120{
120 char *result; 121 char *result;
121 122
122 if (!txt) 123 if (!txt)
123 return txt; 124 return txt;
124 125
125 if (strlen(txt) <= maxlen) 126 if (strlen(txt) <= maxlen)
126 return txt; 127 return txt;
127 result = xmalloc(maxlen + 1); 128 result = xmalloc(maxlen + 1);
128 memcpy(result, txt, maxlen - 3); 129 memcpy(result, txt, maxlen - 3);
129 result[maxlen-1] = result[maxlen-2] = result[maxlen-3] = '.'; 130 result[maxlen-1] = result[maxlen-2] = result[maxlen-3] = '.';
130 result[maxlen] = '\0'; 131 result[maxlen] = '\0';
131 return result; 132 return result;
132} 133}
133 134
134char *strrpart(char *txt, int maxlen) 135char *strrpart(char *txt, int maxlen)
135{ 136{
136 char *result; 137 char *result;
137 138
138 if (!txt) 139 if (!txt)
139 return txt; 140 return txt;
140 141
141 if (strlen(txt) <= maxlen) 142 if (strlen(txt) <= maxlen)
142 return txt; 143 return txt;
143 result = xmalloc(maxlen + 1); 144 result = xmalloc(maxlen + 1);
144 memcpy(result + 3, txt + strlen(txt) - maxlen + 4, maxlen - 3); 145 memcpy(result + 3, txt + strlen(txt) - maxlen + 4, maxlen - 3);
145 result[0] = result[1] = result[2] = '.'; 146 result[0] = result[1] = result[2] = '.';
146 return result; 147 return result;
147} 148}
148 149
149void cgit_add_ref(struct reflist *list, struct refinfo *ref) 150void cgit_add_ref(struct reflist *list, struct refinfo *ref)
150{ 151{
151 size_t size; 152 size_t size;
152 153
153 if (list->count >= list->alloc) { 154 if (list->count >= list->alloc) {
154 list->alloc += (list->alloc ? list->alloc : 4); 155 list->alloc += (list->alloc ? list->alloc : 4);
155 size = list->alloc * sizeof(struct refinfo *); 156 size = list->alloc * sizeof(struct refinfo *);
156 list->refs = xrealloc(list->refs, size); 157 list->refs = xrealloc(list->refs, size);
157 } 158 }
158 list->refs[list->count++] = ref; 159 list->refs[list->count++] = ref;
159} 160}
160 161
diff --git a/ui-repolist.c b/ui-repolist.c
index 2c13d50..25f076f 100644
--- a/ui-repolist.c
+++ b/ui-repolist.c
@@ -180,99 +180,104 @@ struct sortcolumn sortcolumn[] = {
180 {"desc", sort_desc}, 180 {"desc", sort_desc},
181 {"owner", sort_owner}, 181 {"owner", sort_owner},
182 {"idle", sort_idle}, 182 {"idle", sort_idle},
183 {NULL, NULL} 183 {NULL, NULL}
184}; 184};
185 185
186int sort_repolist(char *field) 186int sort_repolist(char *field)
187{ 187{
188 struct sortcolumn *column; 188 struct sortcolumn *column;
189 189
190 for (column = &sortcolumn[0]; column->name; column++) { 190 for (column = &sortcolumn[0]; column->name; column++) {
191 if (strcmp(field, column->name)) 191 if (strcmp(field, column->name))
192 continue; 192 continue;
193 qsort(cgit_repolist.repos, cgit_repolist.count, 193 qsort(cgit_repolist.repos, cgit_repolist.count,
194 sizeof(struct cgit_repo), column->fn); 194 sizeof(struct cgit_repo), column->fn);
195 return 1; 195 return 1;
196 } 196 }
197 return 0; 197 return 0;
198} 198}
199 199
200 200
201void cgit_print_repolist() 201void cgit_print_repolist()
202{ 202{
203 int i, columns = 4, hits = 0, header = 0; 203 int i, columns = 4, hits = 0, header = 0;
204 char *last_group = NULL; 204 char *last_group = NULL;
205 int sorted = 0; 205 int sorted = 0;
206 206
207 if (ctx.cfg.enable_index_links) 207 if (ctx.cfg.enable_index_links)
208 columns++; 208 columns++;
209 209
210 ctx.page.title = ctx.cfg.root_title; 210 ctx.page.title = ctx.cfg.root_title;
211 cgit_print_http_headers(&ctx); 211 cgit_print_http_headers(&ctx);
212 cgit_print_docstart(&ctx); 212 cgit_print_docstart(&ctx);
213 cgit_print_pageheader(&ctx); 213 cgit_print_pageheader(&ctx);
214 214
215 if (ctx.cfg.index_header) 215 if (ctx.cfg.index_header)
216 html_include(ctx.cfg.index_header); 216 html_include(ctx.cfg.index_header);
217 217
218 if(ctx.qry.sort) 218 if(ctx.qry.sort)
219 sorted = sort_repolist(ctx.qry.sort); 219 sorted = sort_repolist(ctx.qry.sort);
220 220
221 html("<table summary='repository list' class='list nowrap'>"); 221 html("<table summary='repository list' class='list nowrap'>");
222 for (i=0; i<cgit_repolist.count; i++) { 222 for (i=0; i<cgit_repolist.count; i++) {
223 ctx.repo = &cgit_repolist.repos[i]; 223 ctx.repo = &cgit_repolist.repos[i];
224 if (!(is_match(ctx.repo) && is_in_url(ctx.repo))) 224 if (!(is_match(ctx.repo) && is_in_url(ctx.repo)))
225 continue; 225 continue;
226 hits++; 226 hits++;
227 if (hits <= ctx.qry.ofs) 227 if (hits <= ctx.qry.ofs)
228 continue; 228 continue;
229 if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count) 229 if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count)
230 continue; 230 continue;
231 if (!header++) 231 if (!header++)
232 print_header(columns); 232 print_header(columns);
233 if (!sorted && 233 if (!sorted &&
234 ((last_group == NULL && ctx.repo->group != NULL) || 234 ((last_group == NULL && ctx.repo->group != NULL) ||
235 (last_group != NULL && ctx.repo->group == NULL) || 235 (last_group != NULL && ctx.repo->group == NULL) ||
236 (last_group != NULL && ctx.repo->group != NULL && 236 (last_group != NULL && ctx.repo->group != NULL &&
237 strcmp(ctx.repo->group, last_group)))) { 237 strcmp(ctx.repo->group, last_group)))) {
238 htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>", 238 htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>",
239 columns); 239 columns);
240 html_txt(ctx.repo->group); 240 html_txt(ctx.repo->group);
241 html("</td></tr>"); 241 html("</td></tr>");
242 last_group = ctx.repo->group; 242 last_group = ctx.repo->group;
243 } 243 }
244 htmlf("<tr><td class='%s'>", 244 htmlf("<tr><td class='%s'>",
245 !sorted && ctx.repo->group ? "sublevel-repo" : "toplevel-repo"); 245 !sorted && ctx.repo->group ? "sublevel-repo" : "toplevel-repo");
246 cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); 246 cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL);
247 html("</td><td>"); 247 html("</td><td>");
248 html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL); 248 html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL);
249 html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc); 249 html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc);
250 html_link_close(); 250 html_link_close();
251 html("</td><td>"); 251 html("</td><td>");
252 html_txt(ctx.repo->owner); 252 html_txt(ctx.repo->owner);
253 html("</td><td>"); 253 html("</td><td>");
254 print_modtime(ctx.repo); 254 print_modtime(ctx.repo);
255 html("</td>"); 255 html("</td>");
256 if (ctx.cfg.enable_index_links) { 256 if (ctx.cfg.enable_index_links) {
257 html("<td>"); 257 html("<td>");
258 cgit_summary_link("summary", NULL, "button", NULL); 258 cgit_summary_link("summary", NULL, "button", NULL);
259 cgit_log_link("log", NULL, "button", NULL, NULL, NULL, 259 cgit_log_link("log", NULL, "button", NULL, NULL, NULL,
260 0, NULL, NULL, ctx.qry.showmsg); 260 0, NULL, NULL, ctx.qry.showmsg);
261 cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); 261 cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL);
262 html("</td>"); 262 html("</td>");
263 } 263 }
264 html("</tr>\n"); 264 html("</tr>\n");
265 } 265 }
266 html("</table>"); 266 html("</table>");
267 if (!hits) 267 if (!hits)
268 cgit_print_error("No repositories found"); 268 cgit_print_error("No repositories found");
269 else if (hits > ctx.cfg.max_repo_count) 269 else if (hits > ctx.cfg.max_repo_count)
270 print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search); 270 print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search);
271 cgit_print_docend(); 271 cgit_print_docend();
272} 272}
273 273
274void cgit_print_site_readme() 274void cgit_print_site_readme()
275{ 275{
276 if (ctx.cfg.root_readme) 276 if (!ctx.cfg.root_readme)
277 html_include(ctx.cfg.root_readme); 277 return;
278 if (ctx.cfg.about_filter)
279 cgit_open_filter(ctx.cfg.about_filter);
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-summary.c b/ui-summary.c
index f2a9b46..a2c018e 100644
--- a/ui-summary.c
+++ b/ui-summary.c
@@ -1,88 +1,92 @@
1/* ui-summary.c: functions for generating repo summary page 1/* ui-summary.c: functions for generating repo summary page
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-log.h" 11#include "ui-log.h"
12#include "ui-refs.h" 12#include "ui-refs.h"
13 13
14int urls = 0; 14int urls = 0;
15 15
16static void print_url(char *base, char *suffix) 16static void print_url(char *base, char *suffix)
17{ 17{
18 if (!base || !*base) 18 if (!base || !*base)
19 return; 19 return;
20 if (urls++ == 0) { 20 if (urls++ == 0) {
21 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>"); 21 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>");
22 html("<tr><th class='left' colspan='4'>Clone</th></tr>\n"); 22 html("<tr><th class='left' colspan='4'>Clone</th></tr>\n");
23 } 23 }
24 if (suffix && *suffix) 24 if (suffix && *suffix)
25 base = fmt("%s/%s", base, suffix); 25 base = fmt("%s/%s", base, suffix);
26 html("<tr><td colspan='4'><a href='"); 26 html("<tr><td colspan='4'><a href='");
27 html_url_path(base); 27 html_url_path(base);
28 html("'>"); 28 html("'>");
29 html_txt(base); 29 html_txt(base);
30 html("</a></td></tr>\n"); 30 html("</a></td></tr>\n");
31} 31}
32 32
33static void print_urls(char *txt, char *suffix) 33static void print_urls(char *txt, char *suffix)
34{ 34{
35 char *h = txt, *t, c; 35 char *h = txt, *t, c;
36 36
37 while (h && *h) { 37 while (h && *h) {
38 while (h && *h == ' ') 38 while (h && *h == ' ')
39 h++; 39 h++;
40 t = h; 40 t = h;
41 while (t && *t && *t != ' ') 41 while (t && *t && *t != ' ')
42 t++; 42 t++;
43 c = *t; 43 c = *t;
44 *t = 0; 44 *t = 0;
45 print_url(h, suffix); 45 print_url(h, suffix);
46 *t = c; 46 *t = c;
47 h = t; 47 h = t;
48 } 48 }
49} 49}
50 50
51void cgit_print_summary() 51void cgit_print_summary()
52{ 52{
53 html("<table summary='repository info' class='list nowrap'>"); 53 html("<table summary='repository info' class='list nowrap'>");
54 cgit_print_branches(ctx.cfg.summary_branches); 54 cgit_print_branches(ctx.cfg.summary_branches);
55 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>"); 55 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>");
56 cgit_print_tags(ctx.cfg.summary_tags); 56 cgit_print_tags(ctx.cfg.summary_tags);
57 if (ctx.cfg.summary_log > 0) { 57 if (ctx.cfg.summary_log > 0) {
58 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>"); 58 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>");
59 cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL, 59 cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL,
60 NULL, NULL, 0); 60 NULL, NULL, 0);
61 } 61 }
62 if (ctx.repo->clone_url) 62 if (ctx.repo->clone_url)
63 print_urls(ctx.repo->clone_url, NULL); 63 print_urls(ctx.repo->clone_url, NULL);
64 else if (ctx.cfg.clone_prefix) 64 else if (ctx.cfg.clone_prefix)
65 print_urls(ctx.cfg.clone_prefix, ctx.repo->url); 65 print_urls(ctx.cfg.clone_prefix, ctx.repo->url);
66 html("</table>"); 66 html("</table>");
67} 67}
68 68
69void cgit_print_repo_readme(char *path) 69void cgit_print_repo_readme(char *path)
70{ 70{
71 char *slash, *tmp; 71 char *slash, *tmp;
72 72
73 if (!ctx.repo->readme) 73 if (!ctx.repo->readme)
74 return; 74 return;
75 75
76 if (path) { 76 if (path) {
77 slash = strrchr(ctx.repo->readme, '/'); 77 slash = strrchr(ctx.repo->readme, '/');
78 if (!slash) 78 if (!slash)
79 return; 79 return;
80 tmp = xmalloc(slash - ctx.repo->readme + 1 + strlen(path) + 1); 80 tmp = xmalloc(slash - ctx.repo->readme + 1 + strlen(path) + 1);
81 strncpy(tmp, ctx.repo->readme, slash - ctx.repo->readme + 1); 81 strncpy(tmp, ctx.repo->readme, slash - ctx.repo->readme + 1);
82 strcpy(tmp + (slash - ctx.repo->readme + 1), path); 82 strcpy(tmp + (slash - ctx.repo->readme + 1), path);
83 } else 83 } else
84 tmp = ctx.repo->readme; 84 tmp = ctx.repo->readme;
85 html("<div id='summary'>"); 85 html("<div id='summary'>");
86 if (ctx.repo->about_filter)
87 cgit_open_filter(ctx.repo->about_filter);
86 html_include(tmp); 88 html_include(tmp);
89 if (ctx.repo->about_filter)
90 cgit_close_filter(ctx.repo->about_filter);
87 html("</div>"); 91 html("</div>");
88} 92}