summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--cgit.c4
-rw-r--r--cgit.h20
-rw-r--r--cgitrc.5.txt6
-rw-r--r--shared.c2
-rw-r--r--ui-commit.c16
-rw-r--r--ui-tree.c8
6 files changed, 35 insertions, 21 deletions
diff --git a/cgit.c b/cgit.c
index 2cda554..fd341b8 100644
--- a/cgit.c
+++ b/cgit.c
@@ -101,96 +101,100 @@ void config_cb(const char *name, const char *value)
101 else if (!strcmp(name, "max-repo-count")) 101 else if (!strcmp(name, "max-repo-count"))
102 ctx.cfg.max_repo_count = atoi(value); 102 ctx.cfg.max_repo_count = atoi(value);
103 else if (!strcmp(name, "max-commit-count")) 103 else if (!strcmp(name, "max-commit-count"))
104 ctx.cfg.max_commit_count = atoi(value); 104 ctx.cfg.max_commit_count = atoi(value);
105 else if (!strcmp(name, "source-filter")) 105 else if (!strcmp(name, "source-filter"))
106 ctx.cfg.source_filter = new_filter(value, 1); 106 ctx.cfg.source_filter = new_filter(value, 1);
107 else if (!strcmp(name, "summary-log")) 107 else if (!strcmp(name, "summary-log"))
108 ctx.cfg.summary_log = atoi(value); 108 ctx.cfg.summary_log = atoi(value);
109 else if (!strcmp(name, "summary-branches")) 109 else if (!strcmp(name, "summary-branches"))
110 ctx.cfg.summary_branches = atoi(value); 110 ctx.cfg.summary_branches = atoi(value);
111 else if (!strcmp(name, "summary-tags")) 111 else if (!strcmp(name, "summary-tags"))
112 ctx.cfg.summary_tags = atoi(value); 112 ctx.cfg.summary_tags = atoi(value);
113 else if (!strcmp(name, "agefile")) 113 else if (!strcmp(name, "agefile"))
114 ctx.cfg.agefile = xstrdup(value); 114 ctx.cfg.agefile = xstrdup(value);
115 else if (!strcmp(name, "renamelimit")) 115 else if (!strcmp(name, "renamelimit"))
116 ctx.cfg.renamelimit = atoi(value); 116 ctx.cfg.renamelimit = atoi(value);
117 else if (!strcmp(name, "robots")) 117 else if (!strcmp(name, "robots"))
118 ctx.cfg.robots = xstrdup(value); 118 ctx.cfg.robots = xstrdup(value);
119 else if (!strcmp(name, "clone-prefix")) 119 else if (!strcmp(name, "clone-prefix"))
120 ctx.cfg.clone_prefix = xstrdup(value); 120 ctx.cfg.clone_prefix = xstrdup(value);
121 else if (!strcmp(name, "local-time")) 121 else if (!strcmp(name, "local-time"))
122 ctx.cfg.local_time = atoi(value); 122 ctx.cfg.local_time = atoi(value);
123 else if (!strcmp(name, "repo.group")) 123 else if (!strcmp(name, "repo.group"))
124 ctx.cfg.repo_group = xstrdup(value); 124 ctx.cfg.repo_group = xstrdup(value);
125 else if (!strcmp(name, "repo.url")) 125 else if (!strcmp(name, "repo.url"))
126 ctx.repo = cgit_add_repo(value); 126 ctx.repo = cgit_add_repo(value);
127 else if (!strcmp(name, "repo.name")) 127 else if (!strcmp(name, "repo.name"))
128 ctx.repo->name = xstrdup(value); 128 ctx.repo->name = xstrdup(value);
129 else if (ctx.repo && !strcmp(name, "repo.path")) 129 else if (ctx.repo && !strcmp(name, "repo.path"))
130 ctx.repo->path = trim_end(value, '/'); 130 ctx.repo->path = trim_end(value, '/');
131 else if (ctx.repo && !strcmp(name, "repo.clone-url")) 131 else if (ctx.repo && !strcmp(name, "repo.clone-url"))
132 ctx.repo->clone_url = xstrdup(value); 132 ctx.repo->clone_url = xstrdup(value);
133 else if (ctx.repo && !strcmp(name, "repo.desc")) 133 else if (ctx.repo && !strcmp(name, "repo.desc"))
134 ctx.repo->desc = xstrdup(value); 134 ctx.repo->desc = xstrdup(value);
135 else if (ctx.repo && !strcmp(name, "repo.owner")) 135 else if (ctx.repo && !strcmp(name, "repo.owner"))
136 ctx.repo->owner = xstrdup(value); 136 ctx.repo->owner = xstrdup(value);
137 else if (ctx.repo && !strcmp(name, "repo.defbranch")) 137 else if (ctx.repo && !strcmp(name, "repo.defbranch"))
138 ctx.repo->defbranch = xstrdup(value); 138 ctx.repo->defbranch = xstrdup(value);
139 else if (ctx.repo && !strcmp(name, "repo.snapshots")) 139 else if (ctx.repo && !strcmp(name, "repo.snapshots"))
140 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ 140 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
141 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) 141 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount"))
142 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 142 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
143 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) 143 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount"))
144 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 144 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
145 else if (ctx.repo && !strcmp(name, "repo.max-stats")) 145 else if (ctx.repo && !strcmp(name, "repo.max-stats"))
146 ctx.repo->max_stats = cgit_find_stats_period(value, NULL); 146 ctx.repo->max_stats = cgit_find_stats_period(value, NULL);
147 else if (ctx.repo && !strcmp(name, "repo.module-link")) 147 else if (ctx.repo && !strcmp(name, "repo.module-link"))
148 ctx.repo->module_link= xstrdup(value); 148 ctx.repo->module_link= xstrdup(value);
149 else if (ctx.repo && !strcmp(name, "repo.commit-filter"))
150 ctx.repo->commit_filter = new_filter(value, 0);
151 else if (ctx.repo && !strcmp(name, "repo.source-filter"))
152 ctx.repo->source_filter = new_filter(value, 1);
149 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { 153 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
150 if (*value == '/') 154 if (*value == '/')
151 ctx.repo->readme = xstrdup(value); 155 ctx.repo->readme = xstrdup(value);
152 else 156 else
153 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); 157 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value));
154 } else if (!strcmp(name, "include")) 158 } else if (!strcmp(name, "include"))
155 parse_configfile(value, config_cb); 159 parse_configfile(value, config_cb);
156} 160}
157 161
158static void querystring_cb(const char *name, const char *value) 162static void querystring_cb(const char *name, const char *value)
159{ 163{
160 if (!strcmp(name,"r")) { 164 if (!strcmp(name,"r")) {
161 ctx.qry.repo = xstrdup(value); 165 ctx.qry.repo = xstrdup(value);
162 ctx.repo = cgit_get_repoinfo(value); 166 ctx.repo = cgit_get_repoinfo(value);
163 } else if (!strcmp(name, "p")) { 167 } else if (!strcmp(name, "p")) {
164 ctx.qry.page = xstrdup(value); 168 ctx.qry.page = xstrdup(value);
165 } else if (!strcmp(name, "url")) { 169 } else if (!strcmp(name, "url")) {
166 ctx.qry.url = xstrdup(value); 170 ctx.qry.url = xstrdup(value);
167 cgit_parse_url(value); 171 cgit_parse_url(value);
168 } else if (!strcmp(name, "qt")) { 172 } else if (!strcmp(name, "qt")) {
169 ctx.qry.grep = xstrdup(value); 173 ctx.qry.grep = xstrdup(value);
170 } else if (!strcmp(name, "q")) { 174 } else if (!strcmp(name, "q")) {
171 ctx.qry.search = xstrdup(value); 175 ctx.qry.search = xstrdup(value);
172 } else if (!strcmp(name, "h")) { 176 } else if (!strcmp(name, "h")) {
173 ctx.qry.head = xstrdup(value); 177 ctx.qry.head = xstrdup(value);
174 ctx.qry.has_symref = 1; 178 ctx.qry.has_symref = 1;
175 } else if (!strcmp(name, "id")) { 179 } else if (!strcmp(name, "id")) {
176 ctx.qry.sha1 = xstrdup(value); 180 ctx.qry.sha1 = xstrdup(value);
177 ctx.qry.has_sha1 = 1; 181 ctx.qry.has_sha1 = 1;
178 } else if (!strcmp(name, "id2")) { 182 } else if (!strcmp(name, "id2")) {
179 ctx.qry.sha2 = xstrdup(value); 183 ctx.qry.sha2 = xstrdup(value);
180 ctx.qry.has_sha1 = 1; 184 ctx.qry.has_sha1 = 1;
181 } else if (!strcmp(name, "ofs")) { 185 } else if (!strcmp(name, "ofs")) {
182 ctx.qry.ofs = atoi(value); 186 ctx.qry.ofs = atoi(value);
183 } else if (!strcmp(name, "path")) { 187 } else if (!strcmp(name, "path")) {
184 ctx.qry.path = trim_end(value, '/'); 188 ctx.qry.path = trim_end(value, '/');
185 } else if (!strcmp(name, "name")) { 189 } else if (!strcmp(name, "name")) {
186 ctx.qry.name = xstrdup(value); 190 ctx.qry.name = xstrdup(value);
187 } else if (!strcmp(name, "mimetype")) { 191 } else if (!strcmp(name, "mimetype")) {
188 ctx.qry.mimetype = xstrdup(value); 192 ctx.qry.mimetype = xstrdup(value);
189 } else if (!strcmp(name, "s")){ 193 } else if (!strcmp(name, "s")){
190 ctx.qry.sort = xstrdup(value); 194 ctx.qry.sort = xstrdup(value);
191 } else if (!strcmp(name, "showmsg")) { 195 } else if (!strcmp(name, "showmsg")) {
192 ctx.qry.showmsg = atoi(value); 196 ctx.qry.showmsg = atoi(value);
193 } else if (!strcmp(name, "period")) { 197 } else if (!strcmp(name, "period")) {
194 ctx.qry.period = xstrdup(value); 198 ctx.qry.period = xstrdup(value);
195 } 199 }
196} 200}
diff --git a/cgit.h b/cgit.h
index 438301d..f10ba05 100644
--- a/cgit.h
+++ b/cgit.h
@@ -3,186 +3,188 @@
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 {
52 char *cmd;
53 char **argv;
54 int old_stdout;
55 int pipe_fh[2];
56 int pid;
57 int exitstatus;
58};
59
51struct cgit_repo { 60struct cgit_repo {
52 char *url; 61 char *url;
53 char *name; 62 char *name;
54 char *path; 63 char *path;
55 char *desc; 64 char *desc;
56 char *owner; 65 char *owner;
57 char *defbranch; 66 char *defbranch;
58 char *group; 67 char *group;
59 char *module_link; 68 char *module_link;
60 char *readme; 69 char *readme;
61 char *clone_url; 70 char *clone_url;
62 int snapshots; 71 int snapshots;
63 int enable_log_filecount; 72 int enable_log_filecount;
64 int enable_log_linecount; 73 int enable_log_linecount;
65 int max_stats; 74 int max_stats;
66 time_t mtime; 75 time_t mtime;
76 struct cgit_filter *commit_filter;
77 struct cgit_filter *source_filter;
67}; 78};
68 79
69struct cgit_repolist { 80struct cgit_repolist {
70 int length; 81 int length;
71 int count; 82 int count;
72 struct cgit_repo *repos; 83 struct cgit_repo *repos;
73}; 84};
74 85
75struct commitinfo { 86struct commitinfo {
76 struct commit *commit; 87 struct commit *commit;
77 char *author; 88 char *author;
78 char *author_email; 89 char *author_email;
79 unsigned long author_date; 90 unsigned long author_date;
80 char *committer; 91 char *committer;
81 char *committer_email; 92 char *committer_email;
82 unsigned long committer_date; 93 unsigned long committer_date;
83 char *subject; 94 char *subject;
84 char *msg; 95 char *msg;
85 char *msg_encoding; 96 char *msg_encoding;
86}; 97};
87 98
88struct taginfo { 99struct taginfo {
89 char *tagger; 100 char *tagger;
90 char *tagger_email; 101 char *tagger_email;
91 unsigned long tagger_date; 102 unsigned long tagger_date;
92 char *msg; 103 char *msg;
93}; 104};
94 105
95struct refinfo { 106struct refinfo {
96 const char *refname; 107 const char *refname;
97 struct object *object; 108 struct object *object;
98 union { 109 union {
99 struct taginfo *tag; 110 struct taginfo *tag;
100 struct commitinfo *commit; 111 struct commitinfo *commit;
101 }; 112 };
102}; 113};
103 114
104struct reflist { 115struct reflist {
105 struct refinfo **refs; 116 struct refinfo **refs;
106 int alloc; 117 int alloc;
107 int count; 118 int count;
108}; 119};
109 120
110struct cgit_query { 121struct cgit_query {
111 int has_symref; 122 int has_symref;
112 int has_sha1; 123 int has_sha1;
113 char *raw; 124 char *raw;
114 char *repo; 125 char *repo;
115 char *page; 126 char *page;
116 char *search; 127 char *search;
117 char *grep; 128 char *grep;
118 char *head; 129 char *head;
119 char *sha1; 130 char *sha1;
120 char *sha2; 131 char *sha2;
121 char *path; 132 char *path;
122 char *name; 133 char *name;
123 char *mimetype; 134 char *mimetype;
124 char *url; 135 char *url;
125 char *period; 136 char *period;
126 int ofs; 137 int ofs;
127 int nohead; 138 int nohead;
128 char *sort; 139 char *sort;
129 int showmsg; 140 int showmsg;
130}; 141};
131 142
132struct cgit_filter {
133 char *cmd;
134 char **argv;
135 int old_stdout;
136 int pipe_fh[2];
137 int pid;
138 int exitstatus;
139};
140
141struct cgit_config { 143struct cgit_config {
142 char *agefile; 144 char *agefile;
143 char *cache_root; 145 char *cache_root;
144 char *clone_prefix; 146 char *clone_prefix;
145 char *css; 147 char *css;
146 char *favicon; 148 char *favicon;
147 char *footer; 149 char *footer;
148 char *head_include; 150 char *head_include;
149 char *header; 151 char *header;
150 char *index_header; 152 char *index_header;
151 char *index_info; 153 char *index_info;
152 char *logo; 154 char *logo;
153 char *logo_link; 155 char *logo_link;
154 char *module_link; 156 char *module_link;
155 char *repo_group; 157 char *repo_group;
156 char *robots; 158 char *robots;
157 char *root_title; 159 char *root_title;
158 char *root_desc; 160 char *root_desc;
159 char *root_readme; 161 char *root_readme;
160 char *script_name; 162 char *script_name;
161 char *virtual_root; 163 char *virtual_root;
162 int cache_size; 164 int cache_size;
163 int cache_dynamic_ttl; 165 int cache_dynamic_ttl;
164 int cache_max_create_time; 166 int cache_max_create_time;
165 int cache_repo_ttl; 167 int cache_repo_ttl;
166 int cache_root_ttl; 168 int cache_root_ttl;
167 int cache_static_ttl; 169 int cache_static_ttl;
168 int embedded; 170 int embedded;
169 int enable_index_links; 171 int enable_index_links;
170 int enable_log_filecount; 172 int enable_log_filecount;
171 int enable_log_linecount; 173 int enable_log_linecount;
172 int local_time; 174 int local_time;
173 int max_repo_count; 175 int max_repo_count;
174 int max_commit_count; 176 int max_commit_count;
175 int max_lock_attempts; 177 int max_lock_attempts;
176 int max_msg_len; 178 int max_msg_len;
177 int max_repodesc_len; 179 int max_repodesc_len;
178 int max_stats; 180 int max_stats;
179 int nocache; 181 int nocache;
180 int noheader; 182 int noheader;
181 int renamelimit; 183 int renamelimit;
182 int snapshots; 184 int snapshots;
183 int summary_branches; 185 int summary_branches;
184 int summary_log; 186 int summary_log;
185 int summary_tags; 187 int summary_tags;
186 struct cgit_filter *commit_filter; 188 struct cgit_filter *commit_filter;
187 struct cgit_filter *source_filter; 189 struct cgit_filter *source_filter;
188}; 190};
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 2efd6aa..ffb3e0f 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -193,136 +193,142 @@ root-readme::
193root-title:: 193root-title::
194 Text printed as heading on the repository index page. Default value: 194 Text printed as heading on the repository index page. Default value:
195 "Git Repository Browser". 195 "Git Repository Browser".
196 196
197snapshots:: 197snapshots::
198 Text which specifies the default (and allowed) set of snapshot formats 198 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 199 supported by cgit. The value is a space-separated list of zero or more
200 of the following values: 200 of the following values:
201 "tar" uncompressed tar-file 201 "tar" uncompressed tar-file
202 "tar.gz"gzip-compressed tar-file 202 "tar.gz"gzip-compressed tar-file
203 "tar.bz2"bzip-compressed tar-file 203 "tar.bz2"bzip-compressed tar-file
204 "zip" zip-file 204 "zip" zip-file
205 Default value: none. 205 Default value: none.
206 206
207source-filter:: 207source-filter::
208 Specifies a command which will be invoked to format plaintext blobs 208 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 209 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 210 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. 211 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: 212 this can be used to implement e.g. syntax highlighting. Default value:
213 none. 213 none.
214 214
215summary-branches:: 215summary-branches::
216 Specifies the number of branches to display in the repository "summary" 216 Specifies the number of branches to display in the repository "summary"
217 view. Default value: "10". 217 view. Default value: "10".
218 218
219summary-log:: 219summary-log::
220 Specifies the number of log entries to display in the repository 220 Specifies the number of log entries to display in the repository
221 "summary" view. Default value: "10". 221 "summary" view. Default value: "10".
222 222
223summary-tags:: 223summary-tags::
224 Specifies the number of tags to display in the repository "summary" 224 Specifies the number of tags to display in the repository "summary"
225 view. Default value: "10". 225 view. Default value: "10".
226 226
227virtual-root:: 227virtual-root::
228 Url which, if specified, will be used as root for all cgit links. It 228 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 229 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 230 '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default
231 value: none. 231 value: none.
232 NOTE: cgit has recently learned how to use PATH_INFO to achieve the 232 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. 233 same kind of virtual urls, so this option will probably be deprecated.
234 234
235REPOSITORY SETTINGS 235REPOSITORY SETTINGS
236------------------- 236-------------------
237repo.clone-url:: 237repo.clone-url::
238 A list of space-separated urls which can be used to clone this repo. 238 A list of space-separated urls which can be used to clone this repo.
239 Default value: none. 239 Default value: none.
240 240
241repo.commit-filter::
242 Override the default commit-filter. Default value: <commit-filter>.
243
241repo.defbranch:: 244repo.defbranch::
242 The name of the default branch for this repository. If no such branch 245 The name of the default branch for this repository. If no such branch
243 exists in the repository, the first branch name (when sorted) is used 246 exists in the repository, the first branch name (when sorted) is used
244 as default instead. Default value: "master". 247 as default instead. Default value: "master".
245 248
246repo.desc:: 249repo.desc::
247 The value to show as repository description. Default value: none. 250 The value to show as repository description. Default value: none.
248 251
249repo.enable-log-filecount:: 252repo.enable-log-filecount::
250 A flag which can be used to disable the global setting 253 A flag which can be used to disable the global setting
251 `enable-log-filecount'. Default value: none. 254 `enable-log-filecount'. Default value: none.
252 255
253repo.enable-log-linecount:: 256repo.enable-log-linecount::
254 A flag which can be used to disable the global setting 257 A flag which can be used to disable the global setting
255 `enable-log-linecount'. Default value: none. 258 `enable-log-linecount'. Default value: none.
256 259
257repo.max-stats:: 260repo.max-stats::
258 Override the default maximum statistics period. Valid values are equal 261 Override the default maximum statistics period. Valid values are equal
259 to the values specified for the global "max-stats" setting. Default 262 to the values specified for the global "max-stats" setting. Default
260 value: none. 263 value: none.
261 264
262repo.name:: 265repo.name::
263 The value to show as repository name. Default value: <repo.url>. 266 The value to show as repository name. Default value: <repo.url>.
264 267
265repo.owner:: 268repo.owner::
266 A value used to identify the owner of the repository. Default value: 269 A value used to identify the owner of the repository. Default value:
267 none. 270 none.
268 271
269repo.path:: 272repo.path::
270 An absolute path to the repository directory. For non-bare repositories 273 An absolute path to the repository directory. For non-bare repositories
271 this is the .git-directory. Default value: none. 274 this is the .git-directory. Default value: none.
272 275
273repo.readme:: 276repo.readme::
274 A path (relative to <repo.path>) which specifies a file to include 277 A path (relative to <repo.path>) which specifies a file to include
275 verbatim as the "About" page for this repo. Default value: none. 278 verbatim as the "About" page for this repo. Default value: none.
276 279
277repo.snapshots:: 280repo.snapshots::
278 A mask of allowed snapshot-formats for this repo, restricted by the 281 A mask of allowed snapshot-formats for this repo, restricted by the
279 "snapshots" global setting. Default value: <snapshots>. 282 "snapshots" global setting. Default value: <snapshots>.
280 283
284repo.source-filter::
285 Override the default source-filter. Default value: <source-filter>.
286
281repo.url:: 287repo.url::
282 The relative url used to access the repository. This must be the first 288 The relative url used to access the repository. This must be the first
283 setting specified for each repo. Default value: none. 289 setting specified for each repo. Default value: none.
284 290
285 291
286EXAMPLE CGITRC FILE 292EXAMPLE CGITRC FILE
287------------------- 293-------------------
288 294
289.... 295....
290# Enable caching of up to 1000 output entriess 296# Enable caching of up to 1000 output entriess
291cache-size=1000 297cache-size=1000
292 298
293 299
294# Specify some default clone prefixes 300# Specify some default clone prefixes
295clone-prefix=git://foobar.com ssh://foobar.com/pub/git http://foobar.com/git 301clone-prefix=git://foobar.com ssh://foobar.com/pub/git http://foobar.com/git
296 302
297# Specify the css url 303# Specify the css url
298css=/css/cgit.css 304css=/css/cgit.css
299 305
300 306
301# Show extra links for each repository on the index page 307# Show extra links for each repository on the index page
302enable-index-links=1 308enable-index-links=1
303 309
304 310
305# Show number of affected files per commit on the log pages 311# Show number of affected files per commit on the log pages
306enable-log-filecount=1 312enable-log-filecount=1
307 313
308 314
309# Show number of added/removed lines per commit on the log pages 315# Show number of added/removed lines per commit on the log pages
310enable-log-linecount=1 316enable-log-linecount=1
311 317
312 318
313# Add a cgit favicon 319# Add a cgit favicon
314favicon=/favicon.ico 320favicon=/favicon.ico
315 321
316 322
317# Use a custom logo 323# Use a custom logo
318logo=/img/mylogo.png 324logo=/img/mylogo.png
319 325
320 326
321# Enable statistics per week, month and quarter 327# Enable statistics per week, month and quarter
322max-stats=quarter 328max-stats=quarter
323 329
324 330
325# Set the title and heading of the repository index page 331# Set the title and heading of the repository index page
326root-title=foobar.com git repositories 332root-title=foobar.com git repositories
327 333
328 334
diff --git a/shared.c b/shared.c
index 288cfa2..783604b 100644
--- a/shared.c
+++ b/shared.c
@@ -17,96 +17,98 @@ int chk_zero(int result, char *msg)
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->commit_filter = ctx.cfg.commit_filter;
66 ret->source_filter = ctx.cfg.source_filter;
65 return ret; 67 return ret;
66} 68}
67 69
68struct cgit_repo *cgit_get_repoinfo(const char *url) 70struct cgit_repo *cgit_get_repoinfo(const char *url)
69{ 71{
70 int i; 72 int i;
71 struct cgit_repo *repo; 73 struct cgit_repo *repo;
72 74
73 for (i=0; i<cgit_repolist.count; i++) { 75 for (i=0; i<cgit_repolist.count; i++) {
74 repo = &cgit_repolist.repos[i]; 76 repo = &cgit_repolist.repos[i];
75 if (!strcmp(repo->url, url)) 77 if (!strcmp(repo->url, url))
76 return repo; 78 return repo;
77 } 79 }
78 return NULL; 80 return NULL;
79} 81}
80 82
81void *cgit_free_commitinfo(struct commitinfo *info) 83void *cgit_free_commitinfo(struct commitinfo *info)
82{ 84{
83 free(info->author); 85 free(info->author);
84 free(info->author_email); 86 free(info->author_email);
85 free(info->committer); 87 free(info->committer);
86 free(info->committer_email); 88 free(info->committer_email);
87 free(info->subject); 89 free(info->subject);
88 free(info->msg); 90 free(info->msg);
89 free(info->msg_encoding); 91 free(info->msg_encoding);
90 free(info); 92 free(info);
91 return NULL; 93 return NULL;
92} 94}
93 95
94char *trim_end(const char *str, char c) 96char *trim_end(const char *str, char c)
95{ 97{
96 int len; 98 int len;
97 char *s, *t; 99 char *s, *t;
98 100
99 if (str == NULL) 101 if (str == NULL)
100 return NULL; 102 return NULL;
101 t = (char *)str; 103 t = (char *)str;
102 len = strlen(t); 104 len = strlen(t);
103 while(len > 0 && t[len - 1] == c) 105 while(len > 0 && t[len - 1] == c)
104 len--; 106 len--;
105 107
106 if (len == 0) 108 if (len == 0)
107 return NULL; 109 return NULL;
108 110
109 c = t[len]; 111 c = t[len];
110 t[len] = '\0'; 112 t[len] = '\0';
111 s = xstrdup(t); 113 s = xstrdup(t);
112 t[len] = c; 114 t[len] = c;
diff --git a/ui-commit.c b/ui-commit.c
index ee0e139..5815b58 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -44,71 +44,71 @@ void cgit_print_commit(char *hex)
44 html_txt(info->author_email); 44 html_txt(info->author_email);
45 html("</td><td class='right'>"); 45 html("</td><td class='right'>");
46 cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time); 46 cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time);
47 html("</td></tr>\n"); 47 html("</td></tr>\n");
48 html("<tr><th>committer</th><td>"); 48 html("<tr><th>committer</th><td>");
49 html_txt(info->committer); 49 html_txt(info->committer);
50 html(" "); 50 html(" ");
51 html_txt(info->committer_email); 51 html_txt(info->committer_email);
52 html("</td><td class='right'>"); 52 html("</td><td class='right'>");
53 cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time); 53 cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time);
54 html("</td></tr>\n"); 54 html("</td></tr>\n");
55 html("<tr><th>commit</th><td colspan='2' class='sha1'>"); 55 html("<tr><th>commit</th><td colspan='2' class='sha1'>");
56 tmp = sha1_to_hex(commit->object.sha1); 56 tmp = sha1_to_hex(commit->object.sha1);
57 cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp); 57 cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp);
58 html(" ("); 58 html(" (");
59 cgit_patch_link("patch", NULL, NULL, NULL, tmp); 59 cgit_patch_link("patch", NULL, NULL, NULL, tmp);
60 html(")</td></tr>\n"); 60 html(")</td></tr>\n");
61 html("<tr><th>tree</th><td colspan='2' class='sha1'>"); 61 html("<tr><th>tree</th><td colspan='2' class='sha1'>");
62 tmp = xstrdup(hex); 62 tmp = xstrdup(hex);
63 cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL, 63 cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL,
64 ctx.qry.head, tmp, NULL); 64 ctx.qry.head, tmp, NULL);
65 html("</td></tr>\n"); 65 html("</td></tr>\n");
66 for (p = commit->parents; p ; p = p->next) { 66 for (p = commit->parents; p ; p = p->next) {
67 parent = lookup_commit_reference(p->item->object.sha1); 67 parent = lookup_commit_reference(p->item->object.sha1);
68 if (!parent) { 68 if (!parent) {
69 html("<tr><td colspan='3'>"); 69 html("<tr><td colspan='3'>");
70 cgit_print_error("Error reading parent commit"); 70 cgit_print_error("Error reading parent commit");
71 html("</td></tr>"); 71 html("</td></tr>");
72 continue; 72 continue;
73 } 73 }
74 html("<tr><th>parent</th>" 74 html("<tr><th>parent</th>"
75 "<td colspan='2' class='sha1'>"); 75 "<td colspan='2' class='sha1'>");
76 cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, 76 cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL,
77 ctx.qry.head, sha1_to_hex(p->item->object.sha1)); 77 ctx.qry.head, sha1_to_hex(p->item->object.sha1));
78 html(" ("); 78 html(" (");
79 cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, 79 cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex,
80 sha1_to_hex(p->item->object.sha1), NULL); 80 sha1_to_hex(p->item->object.sha1), NULL);
81 html(")</td></tr>"); 81 html(")</td></tr>");
82 parents++; 82 parents++;
83 } 83 }
84 if (ctx.repo->snapshots) { 84 if (ctx.repo->snapshots) {
85 html("<tr><th>download</th><td colspan='2' class='sha1'>"); 85 html("<tr><th>download</th><td colspan='2' class='sha1'>");
86 cgit_print_snapshot_links(ctx.qry.repo, ctx.qry.head, 86 cgit_print_snapshot_links(ctx.qry.repo, ctx.qry.head,
87 hex, ctx.repo->snapshots); 87 hex, ctx.repo->snapshots);
88 html("</td></tr>"); 88 html("</td></tr>");
89 } 89 }
90 html("</table>\n"); 90 html("</table>\n");
91 html("<div class='commit-subject'>"); 91 html("<div class='commit-subject'>");
92 if (ctx.cfg.commit_filter) 92 if (ctx.repo->commit_filter)
93 cgit_open_filter(ctx.cfg.commit_filter); 93 cgit_open_filter(ctx.repo->commit_filter);
94 html_txt(info->subject); 94 html_txt(info->subject);
95 if (ctx.cfg.commit_filter) 95 if (ctx.repo->commit_filter)
96 cgit_close_filter(ctx.cfg.commit_filter); 96 cgit_close_filter(ctx.repo->commit_filter);
97 show_commit_decorations(commit); 97 show_commit_decorations(commit);
98 html("</div>"); 98 html("</div>");
99 html("<div class='commit-msg'>"); 99 html("<div class='commit-msg'>");
100 if (ctx.cfg.commit_filter) 100 if (ctx.repo->commit_filter)
101 cgit_open_filter(ctx.cfg.commit_filter); 101 cgit_open_filter(ctx.repo->commit_filter);
102 html_txt(info->msg); 102 html_txt(info->msg);
103 if (ctx.cfg.commit_filter) 103 if (ctx.repo->commit_filter)
104 cgit_close_filter(ctx.cfg.commit_filter); 104 cgit_close_filter(ctx.repo->commit_filter);
105 html("</div>"); 105 html("</div>");
106 if (parents < 3) { 106 if (parents < 3) {
107 if (parents) 107 if (parents)
108 tmp = sha1_to_hex(commit->parents->item->object.sha1); 108 tmp = sha1_to_hex(commit->parents->item->object.sha1);
109 else 109 else
110 tmp = NULL; 110 tmp = NULL;
111 cgit_print_diff(ctx.qry.sha1, tmp, NULL); 111 cgit_print_diff(ctx.qry.sha1, tmp, NULL);
112 } 112 }
113 cgit_free_commitinfo(info); 113 cgit_free_commitinfo(info);
114} 114}
diff --git a/ui-tree.c b/ui-tree.c
index 816e121..caf6a9e 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -1,78 +1,78 @@
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 if (ctx.cfg.source_filter) { 25 if (ctx.repo->source_filter) {
26 html("<tr><td class='lines'><pre><code>"); 26 html("<tr><td class='lines'><pre><code>");
27 ctx.cfg.source_filter->argv[1] = xstrdup(name); 27 ctx.repo->source_filter->argv[1] = xstrdup(name);
28 cgit_open_filter(ctx.cfg.source_filter); 28 cgit_open_filter(ctx.repo->source_filter);
29 write(STDOUT_FILENO, buf, size); 29 write(STDOUT_FILENO, buf, size);
30 cgit_close_filter(ctx.cfg.source_filter); 30 cgit_close_filter(ctx.repo->source_filter);
31 html("</code></pre></td></tr></table>\n"); 31 html("</code></pre></td></tr></table>\n");
32 return; 32 return;
33 } 33 }
34 34
35 html("<tr><td class='linenumbers'><pre>"); 35 html("<tr><td class='linenumbers'><pre>");
36 idx = 0; 36 idx = 0;
37 lineno = 0; 37 lineno = 0;
38 38
39 if (size) { 39 if (size) {
40 htmlf(numberfmt, ++lineno); 40 htmlf(numberfmt, ++lineno);
41 while(idx < size - 1) { // skip absolute last newline 41 while(idx < size - 1) { // skip absolute last newline
42 if (buf[idx] == '\n') 42 if (buf[idx] == '\n')
43 htmlf(numberfmt, ++lineno); 43 htmlf(numberfmt, ++lineno);
44 idx++; 44 idx++;
45 } 45 }
46 } 46 }
47 html("</pre></td>\n"); 47 html("</pre></td>\n");
48 html("<td class='lines'><pre><code>"); 48 html("<td class='lines'><pre><code>");
49 html_txt(buf); 49 html_txt(buf);
50 html("</code></pre></td></tr></table>\n"); 50 html("</code></pre></td></tr></table>\n");
51} 51}
52 52
53#define ROWLEN 32 53#define ROWLEN 32
54 54
55static void print_binary_buffer(char *buf, unsigned long size) 55static void print_binary_buffer(char *buf, unsigned long size)
56{ 56{
57 unsigned long ofs, idx; 57 unsigned long ofs, idx;
58 static char ascii[ROWLEN + 1]; 58 static char ascii[ROWLEN + 1];
59 59
60 html("<table summary='blob content' class='bin-blob'>\n"); 60 html("<table summary='blob content' class='bin-blob'>\n");
61 html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>"); 61 html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>");
62 for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) { 62 for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) {
63 htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs); 63 htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs);
64 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) 64 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
65 htmlf("%*s%02x", 65 htmlf("%*s%02x",
66 idx == 16 ? 4 : 1, "", 66 idx == 16 ? 4 : 1, "",
67 buf[idx] & 0xff); 67 buf[idx] & 0xff);
68 html(" </td><td class='hex'>"); 68 html(" </td><td class='hex'>");
69 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) 69 for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
70 ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.'; 70 ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.';
71 ascii[idx] = '\0'; 71 ascii[idx] = '\0';
72 html_txt(ascii); 72 html_txt(ascii);
73 html("</td></tr>\n"); 73 html("</td></tr>\n");
74 } 74 }
75 html("</table>\n"); 75 html("</table>\n");
76} 76}
77 77
78static void print_object(const unsigned char *sha1, char *path, const char *basename) 78static void print_object(const unsigned char *sha1, char *path, const char *basename)