summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c5
-rw-r--r--cgit.h2
-rw-r--r--cgitrc.5.txt8
-rw-r--r--ui-tree.c2
4 files changed, 9 insertions, 8 deletions
diff --git a/cgit.c b/cgit.c
index a4788cb..ec40e1f 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,338 +1,339 @@
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
20void add_mimetype(const char *name, const char *value) 20void add_mimetype(const char *name, const char *value)
21{ 21{
22 struct string_list_item *item; 22 struct string_list_item *item;
23 23
24 item = string_list_insert(xstrdup(name), &ctx.cfg.mimetypes); 24 item = string_list_insert(xstrdup(name), &ctx.cfg.mimetypes);
25 item->util = xstrdup(value); 25 item->util = xstrdup(value);
26} 26}
27 27
28struct cgit_filter *new_filter(const char *cmd, int extra_args) 28struct cgit_filter *new_filter(const char *cmd, int extra_args)
29{ 29{
30 struct cgit_filter *f; 30 struct cgit_filter *f;
31 31
32 if (!cmd || !cmd[0]) 32 if (!cmd || !cmd[0])
33 return NULL; 33 return NULL;
34 34
35 f = xmalloc(sizeof(struct cgit_filter)); 35 f = xmalloc(sizeof(struct cgit_filter));
36 f->cmd = xstrdup(cmd); 36 f->cmd = xstrdup(cmd);
37 f->argv = xmalloc((2 + extra_args) * sizeof(char *)); 37 f->argv = xmalloc((2 + extra_args) * sizeof(char *));
38 f->argv[0] = f->cmd; 38 f->argv[0] = f->cmd;
39 f->argv[1] = NULL; 39 f->argv[1] = NULL;
40 return f; 40 return f;
41} 41}
42 42
43void config_cb(const char *name, const char *value) 43void config_cb(const char *name, const char *value)
44{ 44{
45 if (!strcmp(name, "root-title")) 45 if (!strcmp(name, "root-title"))
46 ctx.cfg.root_title = xstrdup(value); 46 ctx.cfg.root_title = xstrdup(value);
47 else if (!strcmp(name, "root-desc")) 47 else if (!strcmp(name, "root-desc"))
48 ctx.cfg.root_desc = xstrdup(value); 48 ctx.cfg.root_desc = xstrdup(value);
49 else if (!strcmp(name, "root-readme")) 49 else if (!strcmp(name, "root-readme"))
50 ctx.cfg.root_readme = xstrdup(value); 50 ctx.cfg.root_readme = xstrdup(value);
51 else if (!strcmp(name, "css")) 51 else if (!strcmp(name, "css"))
52 ctx.cfg.css = xstrdup(value); 52 ctx.cfg.css = xstrdup(value);
53 else if (!strcmp(name, "favicon")) 53 else if (!strcmp(name, "favicon"))
54 ctx.cfg.favicon = xstrdup(value); 54 ctx.cfg.favicon = xstrdup(value);
55 else if (!strcmp(name, "footer")) 55 else if (!strcmp(name, "footer"))
56 ctx.cfg.footer = xstrdup(value); 56 ctx.cfg.footer = xstrdup(value);
57 else if (!strcmp(name, "head-include")) 57 else if (!strcmp(name, "head-include"))
58 ctx.cfg.head_include = xstrdup(value); 58 ctx.cfg.head_include = xstrdup(value);
59 else if (!strcmp(name, "header")) 59 else if (!strcmp(name, "header"))
60 ctx.cfg.header = xstrdup(value); 60 ctx.cfg.header = xstrdup(value);
61 else if (!strcmp(name, "logo")) 61 else if (!strcmp(name, "logo"))
62 ctx.cfg.logo = xstrdup(value); 62 ctx.cfg.logo = xstrdup(value);
63 else if (!strcmp(name, "index-header")) 63 else if (!strcmp(name, "index-header"))
64 ctx.cfg.index_header = xstrdup(value); 64 ctx.cfg.index_header = xstrdup(value);
65 else if (!strcmp(name, "index-info")) 65 else if (!strcmp(name, "index-info"))
66 ctx.cfg.index_info = xstrdup(value); 66 ctx.cfg.index_info = xstrdup(value);
67 else if (!strcmp(name, "logo-link")) 67 else if (!strcmp(name, "logo-link"))
68 ctx.cfg.logo_link = xstrdup(value); 68 ctx.cfg.logo_link = xstrdup(value);
69 else if (!strcmp(name, "linenumbers"))
70 ctx.cfg.linenumbers = atoi(value);
71 else if (!strcmp(name, "module-link")) 69 else if (!strcmp(name, "module-link"))
72 ctx.cfg.module_link = xstrdup(value); 70 ctx.cfg.module_link = xstrdup(value);
73 else if (!strcmp(name, "virtual-root")) { 71 else if (!strcmp(name, "virtual-root")) {
74 ctx.cfg.virtual_root = trim_end(value, '/'); 72 ctx.cfg.virtual_root = trim_end(value, '/');
75 if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) 73 if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
76 ctx.cfg.virtual_root = ""; 74 ctx.cfg.virtual_root = "";
77 } else if (!strcmp(name, "nocache")) 75 } else if (!strcmp(name, "nocache"))
78 ctx.cfg.nocache = atoi(value); 76 ctx.cfg.nocache = atoi(value);
79 else if (!strcmp(name, "noplainemail")) 77 else if (!strcmp(name, "noplainemail"))
80 ctx.cfg.noplainemail = atoi(value); 78 ctx.cfg.noplainemail = atoi(value);
81 else if (!strcmp(name, "noheader")) 79 else if (!strcmp(name, "noheader"))
82 ctx.cfg.noheader = atoi(value); 80 ctx.cfg.noheader = atoi(value);
83 else if (!strcmp(name, "snapshots")) 81 else if (!strcmp(name, "snapshots"))
84 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); 82 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
85 else if (!strcmp(name, "enable-index-links")) 83 else if (!strcmp(name, "enable-index-links"))
86 ctx.cfg.enable_index_links = atoi(value); 84 ctx.cfg.enable_index_links = atoi(value);
87 else if (!strcmp(name, "enable-log-filecount")) 85 else if (!strcmp(name, "enable-log-filecount"))
88 ctx.cfg.enable_log_filecount = atoi(value); 86 ctx.cfg.enable_log_filecount = atoi(value);
89 else if (!strcmp(name, "enable-log-linecount")) 87 else if (!strcmp(name, "enable-log-linecount"))
90 ctx.cfg.enable_log_linecount = atoi(value); 88 ctx.cfg.enable_log_linecount = atoi(value);
89 else if (!strcmp(name, "enable-tree-linenumbers"))
90 ctx.cfg.enable_tree_linenumbers = atoi(value);
91 else if (!strcmp(name, "max-stats")) 91 else if (!strcmp(name, "max-stats"))
92 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); 92 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL);
93 else if (!strcmp(name, "cache-size")) 93 else if (!strcmp(name, "cache-size"))
94 ctx.cfg.cache_size = atoi(value); 94 ctx.cfg.cache_size = atoi(value);
95 else if (!strcmp(name, "cache-root")) 95 else if (!strcmp(name, "cache-root"))
96 ctx.cfg.cache_root = xstrdup(value); 96 ctx.cfg.cache_root = xstrdup(value);
97 else if (!strcmp(name, "cache-root-ttl")) 97 else if (!strcmp(name, "cache-root-ttl"))
98 ctx.cfg.cache_root_ttl = atoi(value); 98 ctx.cfg.cache_root_ttl = atoi(value);
99 else if (!strcmp(name, "cache-repo-ttl")) 99 else if (!strcmp(name, "cache-repo-ttl"))
100 ctx.cfg.cache_repo_ttl = atoi(value); 100 ctx.cfg.cache_repo_ttl = atoi(value);
101 else if (!strcmp(name, "cache-static-ttl")) 101 else if (!strcmp(name, "cache-static-ttl"))
102 ctx.cfg.cache_static_ttl = atoi(value); 102 ctx.cfg.cache_static_ttl = atoi(value);
103 else if (!strcmp(name, "cache-dynamic-ttl")) 103 else if (!strcmp(name, "cache-dynamic-ttl"))
104 ctx.cfg.cache_dynamic_ttl = atoi(value); 104 ctx.cfg.cache_dynamic_ttl = atoi(value);
105 else if (!strcmp(name, "about-filter")) 105 else if (!strcmp(name, "about-filter"))
106 ctx.cfg.about_filter = new_filter(value, 0); 106 ctx.cfg.about_filter = new_filter(value, 0);
107 else if (!strcmp(name, "commit-filter")) 107 else if (!strcmp(name, "commit-filter"))
108 ctx.cfg.commit_filter = new_filter(value, 0); 108 ctx.cfg.commit_filter = new_filter(value, 0);
109 else if (!strcmp(name, "embedded")) 109 else if (!strcmp(name, "embedded"))
110 ctx.cfg.embedded = atoi(value); 110 ctx.cfg.embedded = atoi(value);
111 else if (!strcmp(name, "max-message-length")) 111 else if (!strcmp(name, "max-message-length"))
112 ctx.cfg.max_msg_len = atoi(value); 112 ctx.cfg.max_msg_len = atoi(value);
113 else if (!strcmp(name, "max-repodesc-length")) 113 else if (!strcmp(name, "max-repodesc-length"))
114 ctx.cfg.max_repodesc_len = atoi(value); 114 ctx.cfg.max_repodesc_len = atoi(value);
115 else if (!strcmp(name, "max-repo-count")) 115 else if (!strcmp(name, "max-repo-count"))
116 ctx.cfg.max_repo_count = atoi(value); 116 ctx.cfg.max_repo_count = atoi(value);
117 else if (!strcmp(name, "max-commit-count")) 117 else if (!strcmp(name, "max-commit-count"))
118 ctx.cfg.max_commit_count = atoi(value); 118 ctx.cfg.max_commit_count = atoi(value);
119 else if (!strcmp(name, "source-filter")) 119 else if (!strcmp(name, "source-filter"))
120 ctx.cfg.source_filter = new_filter(value, 1); 120 ctx.cfg.source_filter = new_filter(value, 1);
121 else if (!strcmp(name, "summary-log")) 121 else if (!strcmp(name, "summary-log"))
122 ctx.cfg.summary_log = atoi(value); 122 ctx.cfg.summary_log = atoi(value);
123 else if (!strcmp(name, "summary-branches")) 123 else if (!strcmp(name, "summary-branches"))
124 ctx.cfg.summary_branches = atoi(value); 124 ctx.cfg.summary_branches = atoi(value);
125 else if (!strcmp(name, "summary-tags")) 125 else if (!strcmp(name, "summary-tags"))
126 ctx.cfg.summary_tags = atoi(value); 126 ctx.cfg.summary_tags = atoi(value);
127 else if (!strcmp(name, "agefile")) 127 else if (!strcmp(name, "agefile"))
128 ctx.cfg.agefile = xstrdup(value); 128 ctx.cfg.agefile = xstrdup(value);
129 else if (!strcmp(name, "renamelimit")) 129 else if (!strcmp(name, "renamelimit"))
130 ctx.cfg.renamelimit = atoi(value); 130 ctx.cfg.renamelimit = atoi(value);
131 else if (!strcmp(name, "robots")) 131 else if (!strcmp(name, "robots"))
132 ctx.cfg.robots = xstrdup(value); 132 ctx.cfg.robots = xstrdup(value);
133 else if (!strcmp(name, "clone-prefix")) 133 else if (!strcmp(name, "clone-prefix"))
134 ctx.cfg.clone_prefix = xstrdup(value); 134 ctx.cfg.clone_prefix = xstrdup(value);
135 else if (!strcmp(name, "local-time")) 135 else if (!strcmp(name, "local-time"))
136 ctx.cfg.local_time = atoi(value); 136 ctx.cfg.local_time = atoi(value);
137 else if (!prefixcmp(name, "mimetype.")) 137 else if (!prefixcmp(name, "mimetype."))
138 add_mimetype(name + 9, value); 138 add_mimetype(name + 9, value);
139 else if (!strcmp(name, "repo.group")) 139 else if (!strcmp(name, "repo.group"))
140 ctx.cfg.repo_group = xstrdup(value); 140 ctx.cfg.repo_group = xstrdup(value);
141 else if (!strcmp(name, "repo.url")) 141 else if (!strcmp(name, "repo.url"))
142 ctx.repo = cgit_add_repo(value); 142 ctx.repo = cgit_add_repo(value);
143 else if (!strcmp(name, "repo.name")) 143 else if (!strcmp(name, "repo.name"))
144 ctx.repo->name = xstrdup(value); 144 ctx.repo->name = xstrdup(value);
145 else if (ctx.repo && !strcmp(name, "repo.path")) 145 else if (ctx.repo && !strcmp(name, "repo.path"))
146 ctx.repo->path = trim_end(value, '/'); 146 ctx.repo->path = trim_end(value, '/');
147 else if (ctx.repo && !strcmp(name, "repo.clone-url")) 147 else if (ctx.repo && !strcmp(name, "repo.clone-url"))
148 ctx.repo->clone_url = xstrdup(value); 148 ctx.repo->clone_url = xstrdup(value);
149 else if (ctx.repo && !strcmp(name, "repo.desc")) 149 else if (ctx.repo && !strcmp(name, "repo.desc"))
150 ctx.repo->desc = xstrdup(value); 150 ctx.repo->desc = xstrdup(value);
151 else if (ctx.repo && !strcmp(name, "repo.owner")) 151 else if (ctx.repo && !strcmp(name, "repo.owner"))
152 ctx.repo->owner = xstrdup(value); 152 ctx.repo->owner = xstrdup(value);
153 else if (ctx.repo && !strcmp(name, "repo.defbranch")) 153 else if (ctx.repo && !strcmp(name, "repo.defbranch"))
154 ctx.repo->defbranch = xstrdup(value); 154 ctx.repo->defbranch = xstrdup(value);
155 else if (ctx.repo && !strcmp(name, "repo.snapshots")) 155 else if (ctx.repo && !strcmp(name, "repo.snapshots"))
156 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ 156 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
157 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) 157 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount"))
158 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 158 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
159 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) 159 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount"))
160 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 160 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
161 else if (ctx.repo && !strcmp(name, "repo.max-stats")) 161 else if (ctx.repo && !strcmp(name, "repo.max-stats"))
162 ctx.repo->max_stats = cgit_find_stats_period(value, NULL); 162 ctx.repo->max_stats = cgit_find_stats_period(value, NULL);
163 else if (ctx.repo && !strcmp(name, "repo.module-link")) 163 else if (ctx.repo && !strcmp(name, "repo.module-link"))
164 ctx.repo->module_link= xstrdup(value); 164 ctx.repo->module_link= xstrdup(value);
165 else if (ctx.repo && !strcmp(name, "repo.about-filter")) 165 else if (ctx.repo && !strcmp(name, "repo.about-filter"))
166 ctx.repo->about_filter = new_filter(value, 0); 166 ctx.repo->about_filter = new_filter(value, 0);
167 else if (ctx.repo && !strcmp(name, "repo.commit-filter")) 167 else if (ctx.repo && !strcmp(name, "repo.commit-filter"))
168 ctx.repo->commit_filter = new_filter(value, 0); 168 ctx.repo->commit_filter = new_filter(value, 0);
169 else if (ctx.repo && !strcmp(name, "repo.source-filter")) 169 else if (ctx.repo && !strcmp(name, "repo.source-filter"))
170 ctx.repo->source_filter = new_filter(value, 1); 170 ctx.repo->source_filter = new_filter(value, 1);
171 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { 171 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
172 if (*value == '/') 172 if (*value == '/')
173 ctx.repo->readme = xstrdup(value); 173 ctx.repo->readme = xstrdup(value);
174 else 174 else
175 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); 175 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value));
176 } else if (!strcmp(name, "include")) 176 } else if (!strcmp(name, "include"))
177 parse_configfile(value, config_cb); 177 parse_configfile(value, config_cb);
178} 178}
179 179
180static void querystring_cb(const char *name, const char *value) 180static void querystring_cb(const char *name, const char *value)
181{ 181{
182 if (!value) 182 if (!value)
183 value = ""; 183 value = "";
184 184
185 if (!strcmp(name,"r")) { 185 if (!strcmp(name,"r")) {
186 ctx.qry.repo = xstrdup(value); 186 ctx.qry.repo = xstrdup(value);
187 ctx.repo = cgit_get_repoinfo(value); 187 ctx.repo = cgit_get_repoinfo(value);
188 } else if (!strcmp(name, "p")) { 188 } else if (!strcmp(name, "p")) {
189 ctx.qry.page = xstrdup(value); 189 ctx.qry.page = xstrdup(value);
190 } else if (!strcmp(name, "url")) { 190 } else if (!strcmp(name, "url")) {
191 ctx.qry.url = xstrdup(value); 191 ctx.qry.url = xstrdup(value);
192 cgit_parse_url(value); 192 cgit_parse_url(value);
193 } else if (!strcmp(name, "qt")) { 193 } else if (!strcmp(name, "qt")) {
194 ctx.qry.grep = xstrdup(value); 194 ctx.qry.grep = xstrdup(value);
195 } else if (!strcmp(name, "q")) { 195 } else if (!strcmp(name, "q")) {
196 ctx.qry.search = xstrdup(value); 196 ctx.qry.search = xstrdup(value);
197 } else if (!strcmp(name, "h")) { 197 } else if (!strcmp(name, "h")) {
198 ctx.qry.head = xstrdup(value); 198 ctx.qry.head = xstrdup(value);
199 ctx.qry.has_symref = 1; 199 ctx.qry.has_symref = 1;
200 } else if (!strcmp(name, "id")) { 200 } else if (!strcmp(name, "id")) {
201 ctx.qry.sha1 = xstrdup(value); 201 ctx.qry.sha1 = xstrdup(value);
202 ctx.qry.has_sha1 = 1; 202 ctx.qry.has_sha1 = 1;
203 } else if (!strcmp(name, "id2")) { 203 } else if (!strcmp(name, "id2")) {
204 ctx.qry.sha2 = xstrdup(value); 204 ctx.qry.sha2 = xstrdup(value);
205 ctx.qry.has_sha1 = 1; 205 ctx.qry.has_sha1 = 1;
206 } else if (!strcmp(name, "ofs")) { 206 } else if (!strcmp(name, "ofs")) {
207 ctx.qry.ofs = atoi(value); 207 ctx.qry.ofs = atoi(value);
208 } else if (!strcmp(name, "path")) { 208 } else if (!strcmp(name, "path")) {
209 ctx.qry.path = trim_end(value, '/'); 209 ctx.qry.path = trim_end(value, '/');
210 } else if (!strcmp(name, "name")) { 210 } else if (!strcmp(name, "name")) {
211 ctx.qry.name = xstrdup(value); 211 ctx.qry.name = xstrdup(value);
212 } else if (!strcmp(name, "mimetype")) { 212 } else if (!strcmp(name, "mimetype")) {
213 ctx.qry.mimetype = xstrdup(value); 213 ctx.qry.mimetype = xstrdup(value);
214 } else if (!strcmp(name, "s")){ 214 } else if (!strcmp(name, "s")){
215 ctx.qry.sort = xstrdup(value); 215 ctx.qry.sort = xstrdup(value);
216 } else if (!strcmp(name, "showmsg")) { 216 } else if (!strcmp(name, "showmsg")) {
217 ctx.qry.showmsg = atoi(value); 217 ctx.qry.showmsg = atoi(value);
218 } else if (!strcmp(name, "period")) { 218 } else if (!strcmp(name, "period")) {
219 ctx.qry.period = xstrdup(value); 219 ctx.qry.period = xstrdup(value);
220 } 220 }
221} 221}
222 222
223char *xstrdupn(const char *str) 223char *xstrdupn(const char *str)
224{ 224{
225 return (str ? xstrdup(str) : NULL); 225 return (str ? xstrdup(str) : NULL);
226} 226}
227 227
228static void prepare_context(struct cgit_context *ctx) 228static void prepare_context(struct cgit_context *ctx)
229{ 229{
230 memset(ctx, 0, sizeof(ctx)); 230 memset(ctx, 0, sizeof(ctx));
231 ctx->cfg.agefile = "info/web/last-modified"; 231 ctx->cfg.agefile = "info/web/last-modified";
232 ctx->cfg.nocache = 0; 232 ctx->cfg.nocache = 0;
233 ctx->cfg.cache_size = 0; 233 ctx->cfg.cache_size = 0;
234 ctx->cfg.cache_dynamic_ttl = 5; 234 ctx->cfg.cache_dynamic_ttl = 5;
235 ctx->cfg.cache_max_create_time = 5; 235 ctx->cfg.cache_max_create_time = 5;
236 ctx->cfg.cache_repo_ttl = 5; 236 ctx->cfg.cache_repo_ttl = 5;
237 ctx->cfg.cache_root = CGIT_CACHE_ROOT; 237 ctx->cfg.cache_root = CGIT_CACHE_ROOT;
238 ctx->cfg.cache_root_ttl = 5; 238 ctx->cfg.cache_root_ttl = 5;
239 ctx->cfg.cache_static_ttl = -1; 239 ctx->cfg.cache_static_ttl = -1;
240 ctx->cfg.css = "/cgit.css"; 240 ctx->cfg.css = "/cgit.css";
241 ctx->cfg.logo = "/cgit.png"; 241 ctx->cfg.logo = "/cgit.png";
242 ctx->cfg.local_time = 0; 242 ctx->cfg.local_time = 0;
243 ctx->cfg.enable_tree_linenumbers = 1;
243 ctx->cfg.max_repo_count = 50; 244 ctx->cfg.max_repo_count = 50;
244 ctx->cfg.max_commit_count = 50; 245 ctx->cfg.max_commit_count = 50;
245 ctx->cfg.max_lock_attempts = 5; 246 ctx->cfg.max_lock_attempts = 5;
246 ctx->cfg.max_msg_len = 80; 247 ctx->cfg.max_msg_len = 80;
247 ctx->cfg.max_repodesc_len = 80; 248 ctx->cfg.max_repodesc_len = 80;
248 ctx->cfg.max_stats = 0; 249 ctx->cfg.max_stats = 0;
249 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 250 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
250 ctx->cfg.renamelimit = -1; 251 ctx->cfg.renamelimit = -1;
251 ctx->cfg.robots = "index, nofollow"; 252 ctx->cfg.robots = "index, nofollow";
252 ctx->cfg.root_title = "Git repository browser"; 253 ctx->cfg.root_title = "Git repository browser";
253 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 254 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
254 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 255 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
255 ctx->cfg.summary_branches = 10; 256 ctx->cfg.summary_branches = 10;
256 ctx->cfg.summary_log = 10; 257 ctx->cfg.summary_log = 10;
257 ctx->cfg.summary_tags = 10; 258 ctx->cfg.summary_tags = 10;
258 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); 259 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));
259 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); 260 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST"));
260 ctx->env.https = xstrdupn(getenv("HTTPS")); 261 ctx->env.https = xstrdupn(getenv("HTTPS"));
261 ctx->env.no_http = xstrdupn(getenv("NO_HTTP")); 262 ctx->env.no_http = xstrdupn(getenv("NO_HTTP"));
262 ctx->env.path_info = xstrdupn(getenv("PATH_INFO")); 263 ctx->env.path_info = xstrdupn(getenv("PATH_INFO"));
263 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING")); 264 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING"));
264 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD")); 265 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD"));
265 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME")); 266 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
266 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME")); 267 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME"));
267 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT")); 268 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT"));
268 ctx->page.mimetype = "text/html"; 269 ctx->page.mimetype = "text/html";
269 ctx->page.charset = PAGE_ENCODING; 270 ctx->page.charset = PAGE_ENCODING;
270 ctx->page.filename = NULL; 271 ctx->page.filename = NULL;
271 ctx->page.size = 0; 272 ctx->page.size = 0;
272 ctx->page.modified = time(NULL); 273 ctx->page.modified = time(NULL);
273 ctx->page.expires = ctx->page.modified; 274 ctx->page.expires = ctx->page.modified;
274 ctx->page.etag = NULL; 275 ctx->page.etag = NULL;
275 memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list)); 276 memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list));
276 if (ctx->env.script_name) 277 if (ctx->env.script_name)
277 ctx->cfg.script_name = ctx->env.script_name; 278 ctx->cfg.script_name = ctx->env.script_name;
278 if (ctx->env.query_string) 279 if (ctx->env.query_string)
279 ctx->qry.raw = ctx->env.query_string; 280 ctx->qry.raw = ctx->env.query_string;
280 if (!ctx->env.cgit_config) 281 if (!ctx->env.cgit_config)
281 ctx->env.cgit_config = CGIT_CONFIG; 282 ctx->env.cgit_config = CGIT_CONFIG;
282} 283}
283 284
284struct refmatch { 285struct refmatch {
285 char *req_ref; 286 char *req_ref;
286 char *first_ref; 287 char *first_ref;
287 int match; 288 int match;
288}; 289};
289 290
290int find_current_ref(const char *refname, const unsigned char *sha1, 291int find_current_ref(const char *refname, const unsigned char *sha1,
291 int flags, void *cb_data) 292 int flags, void *cb_data)
292{ 293{
293 struct refmatch *info; 294 struct refmatch *info;
294 295
295 info = (struct refmatch *)cb_data; 296 info = (struct refmatch *)cb_data;
296 if (!strcmp(refname, info->req_ref)) 297 if (!strcmp(refname, info->req_ref))
297 info->match = 1; 298 info->match = 1;
298 if (!info->first_ref) 299 if (!info->first_ref)
299 info->first_ref = xstrdup(refname); 300 info->first_ref = xstrdup(refname);
300 return info->match; 301 return info->match;
301} 302}
302 303
303char *find_default_branch(struct cgit_repo *repo) 304char *find_default_branch(struct cgit_repo *repo)
304{ 305{
305 struct refmatch info; 306 struct refmatch info;
306 char *ref; 307 char *ref;
307 308
308 info.req_ref = repo->defbranch; 309 info.req_ref = repo->defbranch;
309 info.first_ref = NULL; 310 info.first_ref = NULL;
310 info.match = 0; 311 info.match = 0;
311 for_each_branch_ref(find_current_ref, &info); 312 for_each_branch_ref(find_current_ref, &info);
312 if (info.match) 313 if (info.match)
313 ref = info.req_ref; 314 ref = info.req_ref;
314 else 315 else
315 ref = info.first_ref; 316 ref = info.first_ref;
316 if (ref) 317 if (ref)
317 ref = xstrdup(ref); 318 ref = xstrdup(ref);
318 return ref; 319 return ref;
319} 320}
320 321
321static int prepare_repo_cmd(struct cgit_context *ctx) 322static int prepare_repo_cmd(struct cgit_context *ctx)
322{ 323{
323 char *tmp; 324 char *tmp;
324 unsigned char sha1[20]; 325 unsigned char sha1[20];
325 int nongit = 0; 326 int nongit = 0;
326 327
327 setenv("GIT_DIR", ctx->repo->path, 1); 328 setenv("GIT_DIR", ctx->repo->path, 1);
328 setup_git_directory_gently(&nongit); 329 setup_git_directory_gently(&nongit);
329 if (nongit) { 330 if (nongit) {
330 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, 331 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
331 "config error"); 332 "config error");
332 tmp = fmt("Not a git repository: '%s'", ctx->repo->path); 333 tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
333 ctx->repo = NULL; 334 ctx->repo = NULL;
334 cgit_print_http_headers(ctx); 335 cgit_print_http_headers(ctx);
335 cgit_print_docstart(ctx); 336 cgit_print_docstart(ctx);
336 cgit_print_pageheader(ctx); 337 cgit_print_pageheader(ctx);
337 cgit_print_error(tmp); 338 cgit_print_error(tmp);
338 cgit_print_docend(); 339 cgit_print_docend();
diff --git a/cgit.h b/cgit.h
index 2fdc531..a20679a 100644
--- a/cgit.h
+++ b/cgit.h
@@ -80,194 +80,194 @@ struct cgit_repo {
80}; 80};
81 81
82struct cgit_repolist { 82struct cgit_repolist {
83 int length; 83 int length;
84 int count; 84 int count;
85 struct cgit_repo *repos; 85 struct cgit_repo *repos;
86}; 86};
87 87
88struct commitinfo { 88struct commitinfo {
89 struct commit *commit; 89 struct commit *commit;
90 char *author; 90 char *author;
91 char *author_email; 91 char *author_email;
92 unsigned long author_date; 92 unsigned long author_date;
93 char *committer; 93 char *committer;
94 char *committer_email; 94 char *committer_email;
95 unsigned long committer_date; 95 unsigned long committer_date;
96 char *subject; 96 char *subject;
97 char *msg; 97 char *msg;
98 char *msg_encoding; 98 char *msg_encoding;
99}; 99};
100 100
101struct taginfo { 101struct taginfo {
102 char *tagger; 102 char *tagger;
103 char *tagger_email; 103 char *tagger_email;
104 unsigned long tagger_date; 104 unsigned long tagger_date;
105 char *msg; 105 char *msg;
106}; 106};
107 107
108struct refinfo { 108struct refinfo {
109 const char *refname; 109 const char *refname;
110 struct object *object; 110 struct object *object;
111 union { 111 union {
112 struct taginfo *tag; 112 struct taginfo *tag;
113 struct commitinfo *commit; 113 struct commitinfo *commit;
114 }; 114 };
115}; 115};
116 116
117struct reflist { 117struct reflist {
118 struct refinfo **refs; 118 struct refinfo **refs;
119 int alloc; 119 int alloc;
120 int count; 120 int count;
121}; 121};
122 122
123struct cgit_query { 123struct cgit_query {
124 int has_symref; 124 int has_symref;
125 int has_sha1; 125 int has_sha1;
126 char *raw; 126 char *raw;
127 char *repo; 127 char *repo;
128 char *page; 128 char *page;
129 char *search; 129 char *search;
130 char *grep; 130 char *grep;
131 char *head; 131 char *head;
132 char *sha1; 132 char *sha1;
133 char *sha2; 133 char *sha2;
134 char *path; 134 char *path;
135 char *name; 135 char *name;
136 char *mimetype; 136 char *mimetype;
137 char *url; 137 char *url;
138 char *period; 138 char *period;
139 int ofs; 139 int ofs;
140 int nohead; 140 int nohead;
141 char *sort; 141 char *sort;
142 int showmsg; 142 int showmsg;
143}; 143};
144 144
145struct cgit_config { 145struct cgit_config {
146 char *agefile; 146 char *agefile;
147 char *cache_root; 147 char *cache_root;
148 char *clone_prefix; 148 char *clone_prefix;
149 char *css; 149 char *css;
150 char *favicon; 150 char *favicon;
151 char *footer; 151 char *footer;
152 char *head_include; 152 char *head_include;
153 char *header; 153 char *header;
154 char *index_header; 154 char *index_header;
155 char *index_info; 155 char *index_info;
156 char *logo; 156 char *logo;
157 char *logo_link; 157 char *logo_link;
158 char *module_link; 158 char *module_link;
159 char *repo_group; 159 char *repo_group;
160 char *robots; 160 char *robots;
161 char *root_title; 161 char *root_title;
162 char *root_desc; 162 char *root_desc;
163 char *root_readme; 163 char *root_readme;
164 char *script_name; 164 char *script_name;
165 char *virtual_root; 165 char *virtual_root;
166 int cache_size; 166 int cache_size;
167 int cache_dynamic_ttl; 167 int cache_dynamic_ttl;
168 int cache_max_create_time; 168 int cache_max_create_time;
169 int cache_repo_ttl; 169 int cache_repo_ttl;
170 int cache_root_ttl; 170 int cache_root_ttl;
171 int cache_static_ttl; 171 int cache_static_ttl;
172 int embedded; 172 int embedded;
173 int enable_index_links; 173 int enable_index_links;
174 int enable_log_filecount; 174 int enable_log_filecount;
175 int enable_log_linecount; 175 int enable_log_linecount;
176 int enable_tree_linenumbers;
176 int local_time; 177 int local_time;
177 int linenumbers;
178 int max_repo_count; 178 int max_repo_count;
179 int max_commit_count; 179 int max_commit_count;
180 int max_lock_attempts; 180 int max_lock_attempts;
181 int max_msg_len; 181 int max_msg_len;
182 int max_repodesc_len; 182 int max_repodesc_len;
183 int max_stats; 183 int max_stats;
184 int nocache; 184 int nocache;
185 int noplainemail; 185 int noplainemail;
186 int noheader; 186 int noheader;
187 int renamelimit; 187 int renamelimit;
188 int snapshots; 188 int snapshots;
189 int summary_branches; 189 int summary_branches;
190 int summary_log; 190 int summary_log;
191 int summary_tags; 191 int summary_tags;
192 struct string_list mimetypes; 192 struct string_list mimetypes;
193 struct cgit_filter *about_filter; 193 struct cgit_filter *about_filter;
194 struct cgit_filter *commit_filter; 194 struct cgit_filter *commit_filter;
195 struct cgit_filter *source_filter; 195 struct cgit_filter *source_filter;
196}; 196};
197 197
198struct cgit_page { 198struct cgit_page {
199 time_t modified; 199 time_t modified;
200 time_t expires; 200 time_t expires;
201 size_t size; 201 size_t size;
202 char *mimetype; 202 char *mimetype;
203 char *charset; 203 char *charset;
204 char *filename; 204 char *filename;
205 char *etag; 205 char *etag;
206 char *title; 206 char *title;
207 int status; 207 int status;
208 char *statusmsg; 208 char *statusmsg;
209}; 209};
210 210
211struct cgit_environment { 211struct cgit_environment {
212 char *cgit_config; 212 char *cgit_config;
213 char *http_host; 213 char *http_host;
214 char *https; 214 char *https;
215 char *no_http; 215 char *no_http;
216 char *path_info; 216 char *path_info;
217 char *query_string; 217 char *query_string;
218 char *request_method; 218 char *request_method;
219 char *script_name; 219 char *script_name;
220 char *server_name; 220 char *server_name;
221 char *server_port; 221 char *server_port;
222}; 222};
223 223
224struct cgit_context { 224struct cgit_context {
225 struct cgit_environment env; 225 struct cgit_environment env;
226 struct cgit_query qry; 226 struct cgit_query qry;
227 struct cgit_config cfg; 227 struct cgit_config cfg;
228 struct cgit_repo *repo; 228 struct cgit_repo *repo;
229 struct cgit_page page; 229 struct cgit_page page;
230}; 230};
231 231
232struct cgit_snapshot_format { 232struct cgit_snapshot_format {
233 const char *suffix; 233 const char *suffix;
234 const char *mimetype; 234 const char *mimetype;
235 write_archive_fn_t write_func; 235 write_archive_fn_t write_func;
236 int bit; 236 int bit;
237}; 237};
238 238
239extern const char *cgit_version; 239extern const char *cgit_version;
240 240
241extern struct cgit_repolist cgit_repolist; 241extern struct cgit_repolist cgit_repolist;
242extern struct cgit_context ctx; 242extern struct cgit_context ctx;
243extern const struct cgit_snapshot_format cgit_snapshot_formats[]; 243extern const struct cgit_snapshot_format cgit_snapshot_formats[];
244 244
245extern struct cgit_repo *cgit_add_repo(const char *url); 245extern struct cgit_repo *cgit_add_repo(const char *url);
246extern struct cgit_repo *cgit_get_repoinfo(const char *url); 246extern struct cgit_repo *cgit_get_repoinfo(const char *url);
247extern void cgit_repo_config_cb(const char *name, const char *value); 247extern void cgit_repo_config_cb(const char *name, const char *value);
248 248
249extern int chk_zero(int result, char *msg); 249extern int chk_zero(int result, char *msg);
250extern int chk_positive(int result, char *msg); 250extern int chk_positive(int result, char *msg);
251extern int chk_non_negative(int result, char *msg); 251extern int chk_non_negative(int result, char *msg);
252 252
253extern char *trim_end(const char *str, char c); 253extern char *trim_end(const char *str, char c);
254extern char *strlpart(char *txt, int maxlen); 254extern char *strlpart(char *txt, int maxlen);
255extern char *strrpart(char *txt, int maxlen); 255extern char *strrpart(char *txt, int maxlen);
256 256
257extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); 257extern void cgit_add_ref(struct reflist *list, struct refinfo *ref);
258extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, 258extern int cgit_refs_cb(const char *refname, const unsigned char *sha1,
259 int flags, void *cb_data); 259 int flags, void *cb_data);
260 260
261extern void *cgit_free_commitinfo(struct commitinfo *info); 261extern void *cgit_free_commitinfo(struct commitinfo *info);
262 262
263extern int cgit_diff_files(const unsigned char *old_sha1, 263extern int cgit_diff_files(const unsigned char *old_sha1,
264 const unsigned char *new_sha1, 264 const unsigned char *new_sha1,
265 unsigned long *old_size, unsigned long *new_size, 265 unsigned long *old_size, unsigned long *new_size,
266 int *binary, linediff_fn fn); 266 int *binary, linediff_fn fn);
267 267
268extern void cgit_diff_tree(const unsigned char *old_sha1, 268extern void cgit_diff_tree(const unsigned char *old_sha1,
269 const unsigned char *new_sha1, 269 const unsigned char *new_sha1,
270 filepair_fn fn, const char *prefix); 270 filepair_fn fn, const char *prefix);
271 271
272extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 272extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
273 273
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index a762ccc..ac5c58c 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -6,243 +6,243 @@ NAME
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
17LOCATION 17LOCATION
18-------- 18--------
19The default location of cgitrc, defined at compile time, is /etc/cgitrc. At 19The default location of cgitrc, defined at compile time, is /etc/cgitrc. At
20runtime, cgit will consult the environment variable CGIT_CONFIG and, if 20runtime, cgit will consult the environment variable CGIT_CONFIG and, if
21defined, use its value instead. 21defined, use its value instead.
22 22
23 23
24GLOBAL SETTINGS 24GLOBAL SETTINGS
25--------------- 25---------------
26about-filter:: 26about-filter::
27 Specifies a command which will be invoked to format the content of 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 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 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: 30 command will be included verbatim on the about page. Default value:
31 none. 31 none.
32 32
33agefile:: 33agefile::
34 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
35 to specify the date and time of the youngest commit in the repository. 35 to specify the date and time of the youngest commit in the repository.
36 The first line in the file is used as input to the "parse_date" 36 The first line in the file is used as input to the "parse_date"
37 function in libgit. Recommended timestamp-format is "yyyy-mm-dd 37 function in libgit. Recommended timestamp-format is "yyyy-mm-dd
38 hh:mm:ss". Default value: "info/web/last-modified". 38 hh:mm:ss". Default value: "info/web/last-modified".
39 39
40cache-root:: 40cache-root::
41 Path used to store the cgit cache entries. Default value: 41 Path used to store the cgit cache entries. Default value:
42 "/var/cache/cgit". 42 "/var/cache/cgit".
43 43
44cache-dynamic-ttl:: 44cache-dynamic-ttl::
45 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
46 version of repository pages accessed without a fixed SHA1. Default 46 version of repository pages accessed without a fixed SHA1. Default
47 value: "5". 47 value: "5".
48 48
49cache-repo-ttl:: 49cache-repo-ttl::
50 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
51 version of the repository summary page. Default value: "5". 51 version of the repository summary page. Default value: "5".
52 52
53cache-root-ttl:: 53cache-root-ttl::
54 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
55 version of the repository index page. Default value: "5". 55 version of the repository index page. Default value: "5".
56 56
57cache-size:: 57cache-size::
58 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"
59 (i.e. caching is disabled). 59 (i.e. caching is disabled).
60 60
61cache-static-ttl:: 61cache-static-ttl::
62 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
63 version of repository pages accessed with a fixed SHA1. Default value: 63 version of repository pages accessed with a fixed SHA1. Default value:
64 "5". 64 "5".
65 65
66clone-prefix:: 66clone-prefix::
67 Space-separated list of common prefixes which, when combined with a 67 Space-separated list of common prefixes which, when combined with a
68 repository url, generates valid clone urls for the repository. This 68 repository url, generates valid clone urls for the repository. This
69 setting is only used if `repo.clone-url` is unspecified. Default value: 69 setting is only used if `repo.clone-url` is unspecified. Default value:
70 none. 70 none.
71 71
72commit-filter:: 72commit-filter::
73 Specifies a command which will be invoked to format commit messages. 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 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 75 command will be included verbatim as the commit message, i.e. this can
76 be used to implement bugtracker integration. Default value: none. 76 be used to implement bugtracker integration. Default value: none.
77 77
78css:: 78css::
79 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.
80 Default value: "/cgit.css". 80 Default value: "/cgit.css".
81 81
82embedded:: 82embedded::
83 Flag which, when set to "1", will make cgit generate a html fragment 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 84 suitable for embedding in other html pages. Default value: none. See
85 also: "noheader". 85 also: "noheader".
86 86
87enable-index-links:: 87enable-index-links::
88 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
89 each repo in the repository index (specifically, to the "summary", 89 each repo in the repository index (specifically, to the "summary",
90 "commit" and "tree" pages). Default value: "0". 90 "commit" and "tree" pages). Default value: "0".
91 91
92enable-log-filecount:: 92enable-log-filecount::
93 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
94 modified files for each commit on the repository log page. Default 94 modified files for each commit on the repository log page. Default
95 value: "0". 95 value: "0".
96 96
97enable-log-linecount:: 97enable-log-linecount::
98 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
99 and removed lines for each commit on the repository log page. Default 99 and removed lines for each commit on the repository log page. Default
100 value: "0". 100 value: "0".
101 101
102enable-tree-linenumbers::
103 Flag which, when set to "1", will make cgit generate linenumber links
104 for plaintext blobs printed in the tree view. Default value: "1".
105
102favicon:: 106favicon::
103 Url used as link to a shortcut icon for cgit. If specified, it is 107 Url used as link to a shortcut icon for cgit. If specified, it is
104 suggested to use the value "/favicon.ico" since certain browsers will 108 suggested to use the value "/favicon.ico" since certain browsers will
105 ignore other values. Default value: none. 109 ignore other values. Default value: none.
106 110
107footer:: 111footer::
108 The content of the file specified with this option will be included 112 The content of the file specified with this option will be included
109 verbatim at the bottom of all pages (i.e. it replaces the standard 113 verbatim at the bottom of all pages (i.e. it replaces the standard
110 "generated by..." message. Default value: none. 114 "generated by..." message. Default value: none.
111 115
112head-include:: 116head-include::
113 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
114 verbatim in the html HEAD section on all pages. Default value: none. 118 verbatim in the html HEAD section on all pages. Default value: none.
115 119
116header:: 120header::
117 The content of the file specified with this option will be included 121 The content of the file specified with this option will be included
118 verbatim at the top of all pages. Default value: none. 122 verbatim at the top of all pages. Default value: none.
119 123
120include:: 124include::
121 Name of a configfile to include before the rest of the current config- 125 Name of a configfile to include before the rest of the current config-
122 file is parsed. Default value: none. 126 file is parsed. Default value: none.
123 127
124index-header:: 128index-header::
125 The content of the file specified with this option will be included 129 The content of the file specified with this option will be included
126 verbatim above the repository index. This setting is deprecated, and 130 verbatim above the repository index. This setting is deprecated, and
127 will not be supported by cgit-1.0 (use root-readme instead). Default 131 will not be supported by cgit-1.0 (use root-readme instead). Default
128 value: none. 132 value: none.
129 133
130index-info:: 134index-info::
131 The content of the file specified with this option will be included 135 The content of the file specified with this option will be included
132 verbatim below the heading on the repository index page. This setting 136 verbatim below the heading on the repository index page. This setting
133 is deprecated, and will not be supported by cgit-1.0 (use root-desc 137 is deprecated, and will not be supported by cgit-1.0 (use root-desc
134 instead). Default value: none. 138 instead). Default value: none.
135 139
136local-time:: 140local-time::
137 Flag which, if set to "1", makes cgit print commit and tag times in the 141 Flag which, if set to "1", makes cgit print commit and tag times in the
138 servers timezone. Default value: "0". 142 servers timezone. Default value: "0".
139 143
140logo:: 144logo::
141 Url which specifies the source of an image which will be used as a logo 145 Url which specifies the source of an image which will be used as a logo
142 on all cgit pages. Default value: "/cgit.png". 146 on all cgit pages. Default value: "/cgit.png".
143 147
144logo-link:: 148logo-link::
145 Url loaded when clicking on the cgit logo image. If unspecified the 149 Url loaded when clicking on the cgit logo image. If unspecified the
146 calculated url of the repository index page will be used. Default 150 calculated url of the repository index page will be used. Default
147 value: none. 151 value: none.
148 152
149linenumbers::
150 If set to "1" lines in tree view will have numbers.
151 Default value: "0".
152
153max-commit-count:: 153max-commit-count::
154 Specifies the number of entries to list per page in "log" view. Default 154 Specifies the number of entries to list per page in "log" view. Default
155 value: "50". 155 value: "50".
156 156
157max-message-length:: 157max-message-length::
158 Specifies the maximum number of commit message characters to display in 158 Specifies the maximum number of commit message characters to display in
159 "log" view. Default value: "80". 159 "log" view. Default value: "80".
160 160
161max-repo-count:: 161max-repo-count::
162 Specifies the number of entries to list per page on therepository 162 Specifies the number of entries to list per page on therepository
163 index page. Default value: "50". 163 index page. Default value: "50".
164 164
165max-repodesc-length:: 165max-repodesc-length::
166 Specifies the maximum number of repo description characters to display 166 Specifies the maximum number of repo description characters to display
167 on the repository index page. Default value: "80". 167 on the repository index page. Default value: "80".
168 168
169max-stats:: 169max-stats::
170 Set the default maximum statistics period. Valid values are "week", 170 Set the default maximum statistics period. Valid values are "week",
171 "month", "quarter" and "year". If unspecified, statistics are 171 "month", "quarter" and "year". If unspecified, statistics are
172 disabled. Default value: none. See also: "repo.max-stats". 172 disabled. Default value: none. See also: "repo.max-stats".
173 173
174mimetype.<ext>:: 174mimetype.<ext>::
175 Set the mimetype for the specified filename extension. This is used 175 Set the mimetype for the specified filename extension. This is used
176 by the `plain` command when returning blob content. 176 by the `plain` command when returning blob content.
177 177
178module-link:: 178module-link::
179 Text which will be used as the formatstring for a hyperlink when a 179 Text which will be used as the formatstring for a hyperlink when a
180 submodule is printed in a directory listing. The arguments for the 180 submodule is printed in a directory listing. The arguments for the
181 formatstring are the path and SHA1 of the submodule commit. Default 181 formatstring are the path and SHA1 of the submodule commit. Default
182 value: "./?repo=%s&page=commit&id=%s" 182 value: "./?repo=%s&page=commit&id=%s"
183 183
184nocache:: 184nocache::
185 If set to the value "1" caching will be disabled. This settings is 185 If set to the value "1" caching will be disabled. This settings is
186 deprecated, and will not be honored starting with cgit-1.0. Default 186 deprecated, and will not be honored starting with cgit-1.0. Default
187 value: "0". 187 value: "0".
188 188
189noplainemail:: 189noplainemail::
190 If set to "1" showing full author email adresses will be disabled. 190 If set to "1" showing full author email adresses will be disabled.
191 Default value: "0". 191 Default value: "0".
192 192
193noheader:: 193noheader::
194 Flag which, when set to "1", will make cgit omit the standard header 194 Flag which, when set to "1", will make cgit omit the standard header
195 on all pages. Default value: none. See also: "embedded". 195 on all pages. Default value: none. See also: "embedded".
196 196
197renamelimit:: 197renamelimit::
198 Maximum number of files to consider when detecting renames. The value 198 Maximum number of files to consider when detecting renames. The value
199 "-1" uses the compiletime value in git (for further info, look at 199 "-1" uses the compiletime value in git (for further info, look at
200 `man git-diff`). Default value: "-1". 200 `man git-diff`). Default value: "-1".
201 201
202repo.group:: 202repo.group::
203 A value for the current repository group, which all repositories 203 A value for the current repository group, which all repositories
204 specified after this setting will inherit. Default value: none. 204 specified after this setting will inherit. Default value: none.
205 205
206robots:: 206robots::
207 Text used as content for the "robots" meta-tag. Default value: 207 Text used as content for the "robots" meta-tag. Default value:
208 "index, nofollow". 208 "index, nofollow".
209 209
210root-desc:: 210root-desc::
211 Text printed below the heading on the repository index page. Default 211 Text printed below the heading on the repository index page. Default
212 value: "a fast webinterface for the git dscm". 212 value: "a fast webinterface for the git dscm".
213 213
214root-readme:: 214root-readme::
215 The content of the file specified with this option will be included 215 The content of the file specified with this option will be included
216 verbatim below the "about" link on the repository index page. Default 216 verbatim below the "about" link on the repository index page. Default
217 value: none. 217 value: none.
218 218
219root-title:: 219root-title::
220 Text printed as heading on the repository index page. Default value: 220 Text printed as heading on the repository index page. Default value:
221 "Git Repository Browser". 221 "Git Repository Browser".
222 222
223snapshots:: 223snapshots::
224 Text which specifies the default (and allowed) set of snapshot formats 224 Text which specifies the default (and allowed) set of snapshot formats
225 supported by cgit. The value is a space-separated list of zero or more 225 supported by cgit. The value is a space-separated list of zero or more
226 of the following values: 226 of the following values:
227 "tar" uncompressed tar-file 227 "tar" uncompressed tar-file
228 "tar.gz"gzip-compressed tar-file 228 "tar.gz"gzip-compressed tar-file
229 "tar.bz2"bzip-compressed tar-file 229 "tar.bz2"bzip-compressed tar-file
230 "zip" zip-file 230 "zip" zip-file
231 Default value: none. 231 Default value: none.
232 232
233source-filter:: 233source-filter::
234 Specifies a command which will be invoked to format plaintext blobs 234 Specifies a command which will be invoked to format plaintext blobs
235 in the tree view. The command will get the blob content on its STDIN 235 in the tree view. The command will get the blob content on its STDIN
236 and the name of the blob as its only command line argument. The STDOUT 236 and the name of the blob as its only command line argument. The STDOUT
237 from the command will be included verbatim as the blob contents, i.e. 237 from the command will be included verbatim as the blob contents, i.e.
238 this can be used to implement e.g. syntax highlighting. Default value: 238 this can be used to implement e.g. syntax highlighting. Default value:
239 none. 239 none.
240 240
241summary-branches:: 241summary-branches::
242 Specifies the number of branches to display in the repository "summary" 242 Specifies the number of branches to display in the repository "summary"
243 view. Default value: "10". 243 view. Default value: "10".
244 244
245summary-log:: 245summary-log::
246 Specifies the number of log entries to display in the repository 246 Specifies the number of log entries to display in the repository
247 "summary" view. Default value: "10". 247 "summary" view. Default value: "10".
248 248
diff --git a/ui-tree.c b/ui-tree.c
index f64e6e0..f53ab64 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -1,122 +1,122 @@
1/* ui-tree.c: functions for tree output 1/* ui-tree.c: functions for tree output
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include <ctype.h> 9#include <ctype.h>
10#include "cgit.h" 10#include "cgit.h"
11#include "html.h" 11#include "html.h"
12#include "ui-shared.h" 12#include "ui-shared.h"
13 13
14char *curr_rev; 14char *curr_rev;
15char *match_path; 15char *match_path;
16int header = 0; 16int header = 0;
17 17
18static void print_text_buffer(const char *name, char *buf, unsigned long size) 18static void print_text_buffer(const char *name, char *buf, unsigned long size)
19{ 19{
20 unsigned long lineno, idx; 20 unsigned long lineno, idx;
21 const char *numberfmt = 21 const char *numberfmt =
22 "<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n"; 22 "<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n";
23 23
24 html("<table summary='blob content' class='blob'>\n"); 24 html("<table summary='blob content' class='blob'>\n");
25 25
26 if (ctx.cfg.linenumbers) { 26 if (ctx.cfg.enable_tree_linenumbers) {
27 html("<tr><td class='linenumbers'><pre>"); 27 html("<tr><td class='linenumbers'><pre>");
28 idx = 0; 28 idx = 0;
29 lineno = 0; 29 lineno = 0;
30 30
31 if (size) { 31 if (size) {
32 htmlf(numberfmt, ++lineno); 32 htmlf(numberfmt, ++lineno);
33 while(idx < size - 1) { // skip absolute last newline 33 while(idx < size - 1) { // skip absolute last newline
34 if (buf[idx] == '\n') 34 if (buf[idx] == '\n')
35 htmlf(numberfmt, ++lineno); 35 htmlf(numberfmt, ++lineno);
36 idx++; 36 idx++;
37 } 37 }
38 } 38 }
39 html("</pre></td>\n"); 39 html("</pre></td>\n");
40 } 40 }
41 else { 41 else {
42 html("<tr>\n"); 42 html("<tr>\n");
43 } 43 }
44 44
45 if (ctx.repo->source_filter) { 45 if (ctx.repo->source_filter) {
46 html("<td class='lines'><pre><code>"); 46 html("<td class='lines'><pre><code>");
47 ctx.repo->source_filter->argv[1] = xstrdup(name); 47 ctx.repo->source_filter->argv[1] = xstrdup(name);
48 cgit_open_filter(ctx.repo->source_filter); 48 cgit_open_filter(ctx.repo->source_filter);
49 write(STDOUT_FILENO, buf, size); 49 write(STDOUT_FILENO, buf, size);
50 cgit_close_filter(ctx.repo->source_filter); 50 cgit_close_filter(ctx.repo->source_filter);
51 html("</code></pre></td></tr></table>\n"); 51 html("</code></pre></td></tr></table>\n");
52 return; 52 return;
53 } 53 }
54 54
55 html("<td class='lines'><pre><code>"); 55 html("<td class='lines'><pre><code>");
56 html_txt(buf); 56 html_txt(buf);
57 html("</code></pre></td></tr></table>\n"); 57 html("</code></pre></td></tr></table>\n");
58} 58}
59 59
60#define ROWLEN 32 60#define ROWLEN 32
61 61
62static void print_binary_buffer(char *buf, unsigned long size) 62static void print_binary_buffer(char *buf, unsigned long size)
63{ 63{
64 unsigned long ofs, idx; 64 unsigned long ofs, idx;
65 static char ascii[ROWLEN + 1]; 65 static char ascii[ROWLEN + 1];
66 66
67 html("<table summary='blob content' class='bin-blob'>\n"); 67 html("<table summary='blob content' class='bin-blob'>\n");
68 html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>"); 68 html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>");
69 for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) { 69 for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) {
70 htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs); 70 htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs);
71 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) 71 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
72 htmlf("%*s%02x", 72 htmlf("%*s%02x",
73 idx == 16 ? 4 : 1, "", 73 idx == 16 ? 4 : 1, "",
74 buf[idx] & 0xff); 74 buf[idx] & 0xff);
75 html(" </td><td class='hex'>"); 75 html(" </td><td class='hex'>");
76 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) 76 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
77 ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.'; 77 ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.';
78 ascii[idx] = '\0'; 78 ascii[idx] = '\0';
79 html_txt(ascii); 79 html_txt(ascii);
80 html("</td></tr>\n"); 80 html("</td></tr>\n");
81 } 81 }
82 html("</table>\n"); 82 html("</table>\n");
83} 83}
84 84
85static void print_object(const unsigned char *sha1, char *path, const char *basename) 85static void print_object(const unsigned char *sha1, char *path, const char *basename)
86{ 86{
87 enum object_type type; 87 enum object_type type;
88 char *buf; 88 char *buf;
89 unsigned long size; 89 unsigned long size;
90 90
91 type = sha1_object_info(sha1, &size); 91 type = sha1_object_info(sha1, &size);
92 if (type == OBJ_BAD) { 92 if (type == OBJ_BAD) {
93 cgit_print_error(fmt("Bad object name: %s", 93 cgit_print_error(fmt("Bad object name: %s",
94 sha1_to_hex(sha1))); 94 sha1_to_hex(sha1)));
95 return; 95 return;
96 } 96 }
97 97
98 buf = read_sha1_file(sha1, &type, &size); 98 buf = read_sha1_file(sha1, &type, &size);
99 if (!buf) { 99 if (!buf) {
100 cgit_print_error(fmt("Error reading object %s", 100 cgit_print_error(fmt("Error reading object %s",
101 sha1_to_hex(sha1))); 101 sha1_to_hex(sha1)));
102 return; 102 return;
103 } 103 }
104 104
105 html(" ("); 105 html(" (");
106 cgit_plain_link("plain", NULL, NULL, ctx.qry.head, 106 cgit_plain_link("plain", NULL, NULL, ctx.qry.head,
107 curr_rev, path); 107 curr_rev, path);
108 htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1)); 108 htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1));
109 109
110 if (buffer_is_binary(buf, size)) 110 if (buffer_is_binary(buf, size))
111 print_binary_buffer(buf, size); 111 print_binary_buffer(buf, size);
112 else 112 else
113 print_text_buffer(basename, buf, size); 113 print_text_buffer(basename, buf, size);
114} 114}
115 115
116 116
117static int ls_item(const unsigned char *sha1, const char *base, int baselen, 117static int ls_item(const unsigned char *sha1, const char *base, int baselen,
118 const char *pathname, unsigned int mode, int stage, 118 const char *pathname, unsigned int mode, int stage,
119 void *cbdata) 119 void *cbdata)
120{ 120{
121 char *name; 121 char *name;
122 char *fullpath; 122 char *fullpath;