summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2010-06-19 09:38:46 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2010-06-19 09:38:46 (UTC)
commit9af580d8f6e31ccd68307a728a710c525e4133ab (patch) (unidiff)
tree30b5fb3d0d323423da7ee52ba9a45b36bb557252
parent023d933121ca7352a069f3886caf6fbe958ba27d (diff)
parent581a0c2a5428917d42cbfb2b4673a2d2ebceb7d0 (diff)
downloadcgit-9af580d8f6e31ccd68307a728a710c525e4133ab.zip
cgit-9af580d8f6e31ccd68307a728a710c525e4133ab.tar.gz
cgit-9af580d8f6e31ccd68307a728a710c525e4133ab.tar.bz2
Merge branch 'sn/subject-link'
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c4
-rw-r--r--cgit.h2
-rw-r--r--cgitrc.5.txt10
-rw-r--r--shared.c1
-rw-r--r--ui-commit.c12
5 files changed, 25 insertions, 4 deletions
diff --git a/cgit.c b/cgit.c
index 9305d0a..6ccf4aa 100644
--- a/cgit.c
+++ b/cgit.c
@@ -17,175 +17,179 @@
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
43static void process_cached_repolist(const char *path); 43static void process_cached_repolist(const char *path);
44 44
45void repo_config(struct cgit_repo *repo, const char *name, const char *value) 45void repo_config(struct cgit_repo *repo, const char *name, const char *value)
46{ 46{
47 if (!strcmp(name, "name")) 47 if (!strcmp(name, "name"))
48 repo->name = xstrdup(value); 48 repo->name = xstrdup(value);
49 else if (!strcmp(name, "clone-url")) 49 else if (!strcmp(name, "clone-url"))
50 repo->clone_url = xstrdup(value); 50 repo->clone_url = xstrdup(value);
51 else if (!strcmp(name, "desc")) 51 else if (!strcmp(name, "desc"))
52 repo->desc = xstrdup(value); 52 repo->desc = xstrdup(value);
53 else if (!strcmp(name, "owner")) 53 else if (!strcmp(name, "owner"))
54 repo->owner = xstrdup(value); 54 repo->owner = xstrdup(value);
55 else if (!strcmp(name, "defbranch")) 55 else if (!strcmp(name, "defbranch"))
56 repo->defbranch = xstrdup(value); 56 repo->defbranch = xstrdup(value);
57 else if (!strcmp(name, "snapshots")) 57 else if (!strcmp(name, "snapshots"))
58 repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); 58 repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value);
59 else if (!strcmp(name, "enable-log-filecount")) 59 else if (!strcmp(name, "enable-log-filecount"))
60 repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 60 repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
61 else if (!strcmp(name, "enable-log-linecount")) 61 else if (!strcmp(name, "enable-log-linecount"))
62 repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 62 repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
63 else if (!strcmp(name, "enable-remote-branches")) 63 else if (!strcmp(name, "enable-remote-branches"))
64 repo->enable_remote_branches = atoi(value); 64 repo->enable_remote_branches = atoi(value);
65 else if (!strcmp(name, "enable-subject-links"))
66 repo->enable_subject_links = atoi(value);
65 else if (!strcmp(name, "max-stats")) 67 else if (!strcmp(name, "max-stats"))
66 repo->max_stats = cgit_find_stats_period(value, NULL); 68 repo->max_stats = cgit_find_stats_period(value, NULL);
67 else if (!strcmp(name, "module-link")) 69 else if (!strcmp(name, "module-link"))
68 repo->module_link= xstrdup(value); 70 repo->module_link= xstrdup(value);
69 else if (!strcmp(name, "section")) 71 else if (!strcmp(name, "section"))
70 repo->section = xstrdup(value); 72 repo->section = xstrdup(value);
71 else if (!strcmp(name, "readme") && value != NULL) { 73 else if (!strcmp(name, "readme") && value != NULL) {
72 if (*value == '/') 74 if (*value == '/')
73 repo->readme = xstrdup(value); 75 repo->readme = xstrdup(value);
74 else 76 else
75 repo->readme = xstrdup(fmt("%s/%s", repo->path, value)); 77 repo->readme = xstrdup(fmt("%s/%s", repo->path, value));
76 } else if (ctx.cfg.enable_filter_overrides) { 78 } else if (ctx.cfg.enable_filter_overrides) {
77 if (!strcmp(name, "about-filter")) 79 if (!strcmp(name, "about-filter"))
78 repo->about_filter = new_filter(value, 0); 80 repo->about_filter = new_filter(value, 0);
79 else if (!strcmp(name, "commit-filter")) 81 else if (!strcmp(name, "commit-filter"))
80 repo->commit_filter = new_filter(value, 0); 82 repo->commit_filter = new_filter(value, 0);
81 else if (!strcmp(name, "source-filter")) 83 else if (!strcmp(name, "source-filter"))
82 repo->source_filter = new_filter(value, 1); 84 repo->source_filter = new_filter(value, 1);
83 } 85 }
84} 86}
85 87
86void config_cb(const char *name, const char *value) 88void config_cb(const char *name, const char *value)
87{ 89{
88 if (!strcmp(name, "section") || !strcmp(name, "repo.group")) 90 if (!strcmp(name, "section") || !strcmp(name, "repo.group"))
89 ctx.cfg.section = xstrdup(value); 91 ctx.cfg.section = xstrdup(value);
90 else if (!strcmp(name, "repo.url")) 92 else if (!strcmp(name, "repo.url"))
91 ctx.repo = cgit_add_repo(value); 93 ctx.repo = cgit_add_repo(value);
92 else if (ctx.repo && !strcmp(name, "repo.path")) 94 else if (ctx.repo && !strcmp(name, "repo.path"))
93 ctx.repo->path = trim_end(value, '/'); 95 ctx.repo->path = trim_end(value, '/');
94 else if (ctx.repo && !prefixcmp(name, "repo.")) 96 else if (ctx.repo && !prefixcmp(name, "repo."))
95 repo_config(ctx.repo, name + 5, value); 97 repo_config(ctx.repo, name + 5, value);
96 else if (!strcmp(name, "root-title")) 98 else if (!strcmp(name, "root-title"))
97 ctx.cfg.root_title = xstrdup(value); 99 ctx.cfg.root_title = xstrdup(value);
98 else if (!strcmp(name, "root-desc")) 100 else if (!strcmp(name, "root-desc"))
99 ctx.cfg.root_desc = xstrdup(value); 101 ctx.cfg.root_desc = xstrdup(value);
100 else if (!strcmp(name, "root-readme")) 102 else if (!strcmp(name, "root-readme"))
101 ctx.cfg.root_readme = xstrdup(value); 103 ctx.cfg.root_readme = xstrdup(value);
102 else if (!strcmp(name, "css")) 104 else if (!strcmp(name, "css"))
103 ctx.cfg.css = xstrdup(value); 105 ctx.cfg.css = xstrdup(value);
104 else if (!strcmp(name, "favicon")) 106 else if (!strcmp(name, "favicon"))
105 ctx.cfg.favicon = xstrdup(value); 107 ctx.cfg.favicon = xstrdup(value);
106 else if (!strcmp(name, "footer")) 108 else if (!strcmp(name, "footer"))
107 ctx.cfg.footer = xstrdup(value); 109 ctx.cfg.footer = xstrdup(value);
108 else if (!strcmp(name, "head-include")) 110 else if (!strcmp(name, "head-include"))
109 ctx.cfg.head_include = xstrdup(value); 111 ctx.cfg.head_include = xstrdup(value);
110 else if (!strcmp(name, "header")) 112 else if (!strcmp(name, "header"))
111 ctx.cfg.header = xstrdup(value); 113 ctx.cfg.header = xstrdup(value);
112 else if (!strcmp(name, "logo")) 114 else if (!strcmp(name, "logo"))
113 ctx.cfg.logo = xstrdup(value); 115 ctx.cfg.logo = xstrdup(value);
114 else if (!strcmp(name, "index-header")) 116 else if (!strcmp(name, "index-header"))
115 ctx.cfg.index_header = xstrdup(value); 117 ctx.cfg.index_header = xstrdup(value);
116 else if (!strcmp(name, "index-info")) 118 else if (!strcmp(name, "index-info"))
117 ctx.cfg.index_info = xstrdup(value); 119 ctx.cfg.index_info = xstrdup(value);
118 else if (!strcmp(name, "logo-link")) 120 else if (!strcmp(name, "logo-link"))
119 ctx.cfg.logo_link = xstrdup(value); 121 ctx.cfg.logo_link = xstrdup(value);
120 else if (!strcmp(name, "module-link")) 122 else if (!strcmp(name, "module-link"))
121 ctx.cfg.module_link = xstrdup(value); 123 ctx.cfg.module_link = xstrdup(value);
122 else if (!strcmp(name, "virtual-root")) { 124 else if (!strcmp(name, "virtual-root")) {
123 ctx.cfg.virtual_root = trim_end(value, '/'); 125 ctx.cfg.virtual_root = trim_end(value, '/');
124 if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) 126 if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
125 ctx.cfg.virtual_root = ""; 127 ctx.cfg.virtual_root = "";
126 } else if (!strcmp(name, "nocache")) 128 } else if (!strcmp(name, "nocache"))
127 ctx.cfg.nocache = atoi(value); 129 ctx.cfg.nocache = atoi(value);
128 else if (!strcmp(name, "noplainemail")) 130 else if (!strcmp(name, "noplainemail"))
129 ctx.cfg.noplainemail = atoi(value); 131 ctx.cfg.noplainemail = atoi(value);
130 else if (!strcmp(name, "noheader")) 132 else if (!strcmp(name, "noheader"))
131 ctx.cfg.noheader = atoi(value); 133 ctx.cfg.noheader = atoi(value);
132 else if (!strcmp(name, "snapshots")) 134 else if (!strcmp(name, "snapshots"))
133 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); 135 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
134 else if (!strcmp(name, "enable-filter-overrides")) 136 else if (!strcmp(name, "enable-filter-overrides"))
135 ctx.cfg.enable_filter_overrides = atoi(value); 137 ctx.cfg.enable_filter_overrides = atoi(value);
136 else if (!strcmp(name, "enable-index-links")) 138 else if (!strcmp(name, "enable-index-links"))
137 ctx.cfg.enable_index_links = atoi(value); 139 ctx.cfg.enable_index_links = atoi(value);
138 else if (!strcmp(name, "enable-log-filecount")) 140 else if (!strcmp(name, "enable-log-filecount"))
139 ctx.cfg.enable_log_filecount = atoi(value); 141 ctx.cfg.enable_log_filecount = atoi(value);
140 else if (!strcmp(name, "enable-log-linecount")) 142 else if (!strcmp(name, "enable-log-linecount"))
141 ctx.cfg.enable_log_linecount = atoi(value); 143 ctx.cfg.enable_log_linecount = atoi(value);
142 else if (!strcmp(name, "enable-remote-branches")) 144 else if (!strcmp(name, "enable-remote-branches"))
143 ctx.cfg.enable_remote_branches = atoi(value); 145 ctx.cfg.enable_remote_branches = atoi(value);
146 else if (!strcmp(name, "enable-subject-links"))
147 ctx.cfg.enable_subject_links = atoi(value);
144 else if (!strcmp(name, "enable-tree-linenumbers")) 148 else if (!strcmp(name, "enable-tree-linenumbers"))
145 ctx.cfg.enable_tree_linenumbers = atoi(value); 149 ctx.cfg.enable_tree_linenumbers = atoi(value);
146 else if (!strcmp(name, "max-stats")) 150 else if (!strcmp(name, "max-stats"))
147 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); 151 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL);
148 else if (!strcmp(name, "cache-size")) 152 else if (!strcmp(name, "cache-size"))
149 ctx.cfg.cache_size = atoi(value); 153 ctx.cfg.cache_size = atoi(value);
150 else if (!strcmp(name, "cache-root")) 154 else if (!strcmp(name, "cache-root"))
151 ctx.cfg.cache_root = xstrdup(value); 155 ctx.cfg.cache_root = xstrdup(value);
152 else if (!strcmp(name, "cache-root-ttl")) 156 else if (!strcmp(name, "cache-root-ttl"))
153 ctx.cfg.cache_root_ttl = atoi(value); 157 ctx.cfg.cache_root_ttl = atoi(value);
154 else if (!strcmp(name, "cache-repo-ttl")) 158 else if (!strcmp(name, "cache-repo-ttl"))
155 ctx.cfg.cache_repo_ttl = atoi(value); 159 ctx.cfg.cache_repo_ttl = atoi(value);
156 else if (!strcmp(name, "cache-scanrc-ttl")) 160 else if (!strcmp(name, "cache-scanrc-ttl"))
157 ctx.cfg.cache_scanrc_ttl = atoi(value); 161 ctx.cfg.cache_scanrc_ttl = atoi(value);
158 else if (!strcmp(name, "cache-static-ttl")) 162 else if (!strcmp(name, "cache-static-ttl"))
159 ctx.cfg.cache_static_ttl = atoi(value); 163 ctx.cfg.cache_static_ttl = atoi(value);
160 else if (!strcmp(name, "cache-dynamic-ttl")) 164 else if (!strcmp(name, "cache-dynamic-ttl"))
161 ctx.cfg.cache_dynamic_ttl = atoi(value); 165 ctx.cfg.cache_dynamic_ttl = atoi(value);
162 else if (!strcmp(name, "about-filter")) 166 else if (!strcmp(name, "about-filter"))
163 ctx.cfg.about_filter = new_filter(value, 0); 167 ctx.cfg.about_filter = new_filter(value, 0);
164 else if (!strcmp(name, "commit-filter")) 168 else if (!strcmp(name, "commit-filter"))
165 ctx.cfg.commit_filter = new_filter(value, 0); 169 ctx.cfg.commit_filter = new_filter(value, 0);
166 else if (!strcmp(name, "embedded")) 170 else if (!strcmp(name, "embedded"))
167 ctx.cfg.embedded = atoi(value); 171 ctx.cfg.embedded = atoi(value);
168 else if (!strcmp(name, "max-message-length")) 172 else if (!strcmp(name, "max-message-length"))
169 ctx.cfg.max_msg_len = atoi(value); 173 ctx.cfg.max_msg_len = atoi(value);
170 else if (!strcmp(name, "max-repodesc-length")) 174 else if (!strcmp(name, "max-repodesc-length"))
171 ctx.cfg.max_repodesc_len = atoi(value); 175 ctx.cfg.max_repodesc_len = atoi(value);
172 else if (!strcmp(name, "max-blob-size")) 176 else if (!strcmp(name, "max-blob-size"))
173 ctx.cfg.max_blob_size = atoi(value); 177 ctx.cfg.max_blob_size = atoi(value);
174 else if (!strcmp(name, "max-repo-count")) 178 else if (!strcmp(name, "max-repo-count"))
175 ctx.cfg.max_repo_count = atoi(value); 179 ctx.cfg.max_repo_count = atoi(value);
176 else if (!strcmp(name, "max-commit-count")) 180 else if (!strcmp(name, "max-commit-count"))
177 ctx.cfg.max_commit_count = atoi(value); 181 ctx.cfg.max_commit_count = atoi(value);
178 else if (!strcmp(name, "scan-path")) 182 else if (!strcmp(name, "scan-path"))
179 if (!ctx.cfg.nocache && ctx.cfg.cache_size) 183 if (!ctx.cfg.nocache && ctx.cfg.cache_size)
180 process_cached_repolist(value); 184 process_cached_repolist(value);
181 else 185 else
182 scan_tree(value, repo_config); 186 scan_tree(value, repo_config);
183 else if (!strcmp(name, "source-filter")) 187 else if (!strcmp(name, "source-filter"))
184 ctx.cfg.source_filter = new_filter(value, 1); 188 ctx.cfg.source_filter = new_filter(value, 1);
185 else if (!strcmp(name, "summary-log")) 189 else if (!strcmp(name, "summary-log"))
186 ctx.cfg.summary_log = atoi(value); 190 ctx.cfg.summary_log = atoi(value);
187 else if (!strcmp(name, "summary-branches")) 191 else if (!strcmp(name, "summary-branches"))
188 ctx.cfg.summary_branches = atoi(value); 192 ctx.cfg.summary_branches = atoi(value);
189 else if (!strcmp(name, "summary-tags")) 193 else if (!strcmp(name, "summary-tags"))
190 ctx.cfg.summary_tags = atoi(value); 194 ctx.cfg.summary_tags = atoi(value);
191 else if (!strcmp(name, "side-by-side-diffs")) 195 else if (!strcmp(name, "side-by-side-diffs"))
diff --git a/cgit.h b/cgit.h
index cd4af72..9b1e3f8 100644
--- a/cgit.h
+++ b/cgit.h
@@ -28,96 +28,97 @@
28#define FMT_SHORTDATE "%Y-%m-%d" 28#define FMT_SHORTDATE "%Y-%m-%d"
29#define FMT_ATOMDATE "%Y-%m-%dT%H:%M:%SZ" 29#define FMT_ATOMDATE "%Y-%m-%dT%H:%M:%SZ"
30 30
31 31
32/* 32/*
33 * Limits used for relative dates 33 * Limits used for relative dates
34 */ 34 */
35#define TM_MIN 60 35#define TM_MIN 60
36#define TM_HOUR (TM_MIN * 60) 36#define TM_HOUR (TM_MIN * 60)
37#define TM_DAY (TM_HOUR * 24) 37#define TM_DAY (TM_HOUR * 24)
38#define TM_WEEK (TM_DAY * 7) 38#define TM_WEEK (TM_DAY * 7)
39#define TM_YEAR (TM_DAY * 365) 39#define TM_YEAR (TM_DAY * 365)
40#define TM_MONTH (TM_YEAR / 12.0) 40#define TM_MONTH (TM_YEAR / 12.0)
41 41
42 42
43/* 43/*
44 * Default encoding 44 * Default encoding
45 */ 45 */
46#define PAGE_ENCODING "UTF-8" 46#define PAGE_ENCODING "UTF-8"
47 47
48typedef void (*configfn)(const char *name, const char *value); 48typedef void (*configfn)(const char *name, const char *value);
49typedef void (*filepair_fn)(struct diff_filepair *pair); 49typedef void (*filepair_fn)(struct diff_filepair *pair);
50typedef void (*linediff_fn)(char *line, int len); 50typedef void (*linediff_fn)(char *line, int len);
51 51
52struct cgit_filter { 52struct cgit_filter {
53 char *cmd; 53 char *cmd;
54 char **argv; 54 char **argv;
55 int old_stdout; 55 int old_stdout;
56 int pipe_fh[2]; 56 int pipe_fh[2];
57 int pid; 57 int pid;
58 int exitstatus; 58 int exitstatus;
59}; 59};
60 60
61struct cgit_repo { 61struct cgit_repo {
62 char *url; 62 char *url;
63 char *name; 63 char *name;
64 char *path; 64 char *path;
65 char *desc; 65 char *desc;
66 char *owner; 66 char *owner;
67 char *defbranch; 67 char *defbranch;
68 char *module_link; 68 char *module_link;
69 char *readme; 69 char *readme;
70 char *section; 70 char *section;
71 char *clone_url; 71 char *clone_url;
72 int snapshots; 72 int snapshots;
73 int enable_log_filecount; 73 int enable_log_filecount;
74 int enable_log_linecount; 74 int enable_log_linecount;
75 int enable_remote_branches; 75 int enable_remote_branches;
76 int enable_subject_links;
76 int max_stats; 77 int max_stats;
77 time_t mtime; 78 time_t mtime;
78 struct cgit_filter *about_filter; 79 struct cgit_filter *about_filter;
79 struct cgit_filter *commit_filter; 80 struct cgit_filter *commit_filter;
80 struct cgit_filter *source_filter; 81 struct cgit_filter *source_filter;
81}; 82};
82 83
83typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name, 84typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name,
84 const char *value); 85 const char *value);
85 86
86struct cgit_repolist { 87struct cgit_repolist {
87 int length; 88 int length;
88 int count; 89 int count;
89 struct cgit_repo *repos; 90 struct cgit_repo *repos;
90}; 91};
91 92
92struct commitinfo { 93struct commitinfo {
93 struct commit *commit; 94 struct commit *commit;
94 char *author; 95 char *author;
95 char *author_email; 96 char *author_email;
96 unsigned long author_date; 97 unsigned long author_date;
97 char *committer; 98 char *committer;
98 char *committer_email; 99 char *committer_email;
99 unsigned long committer_date; 100 unsigned long committer_date;
100 char *subject; 101 char *subject;
101 char *msg; 102 char *msg;
102 char *msg_encoding; 103 char *msg_encoding;
103}; 104};
104 105
105struct taginfo { 106struct taginfo {
106 char *tagger; 107 char *tagger;
107 char *tagger_email; 108 char *tagger_email;
108 unsigned long tagger_date; 109 unsigned long tagger_date;
109 char *msg; 110 char *msg;
110}; 111};
111 112
112struct refinfo { 113struct refinfo {
113 const char *refname; 114 const char *refname;
114 struct object *object; 115 struct object *object;
115 union { 116 union {
116 struct taginfo *tag; 117 struct taginfo *tag;
117 struct commitinfo *commit; 118 struct commitinfo *commit;
118 }; 119 };
119}; 120};
120 121
121struct reflist { 122struct reflist {
122 struct refinfo **refs; 123 struct refinfo **refs;
123 int alloc; 124 int alloc;
@@ -136,96 +137,97 @@ struct cgit_query {
136 char *sha1; 137 char *sha1;
137 char *sha2; 138 char *sha2;
138 char *path; 139 char *path;
139 char *name; 140 char *name;
140 char *mimetype; 141 char *mimetype;
141 char *url; 142 char *url;
142 char *period; 143 char *period;
143 int ofs; 144 int ofs;
144 int nohead; 145 int nohead;
145 char *sort; 146 char *sort;
146 int showmsg; 147 int showmsg;
147 int ssdiff; 148 int ssdiff;
148}; 149};
149 150
150struct cgit_config { 151struct cgit_config {
151 char *agefile; 152 char *agefile;
152 char *cache_root; 153 char *cache_root;
153 char *clone_prefix; 154 char *clone_prefix;
154 char *css; 155 char *css;
155 char *favicon; 156 char *favicon;
156 char *footer; 157 char *footer;
157 char *head_include; 158 char *head_include;
158 char *header; 159 char *header;
159 char *index_header; 160 char *index_header;
160 char *index_info; 161 char *index_info;
161 char *logo; 162 char *logo;
162 char *logo_link; 163 char *logo_link;
163 char *module_link; 164 char *module_link;
164 char *robots; 165 char *robots;
165 char *root_title; 166 char *root_title;
166 char *root_desc; 167 char *root_desc;
167 char *root_readme; 168 char *root_readme;
168 char *script_name; 169 char *script_name;
169 char *section; 170 char *section;
170 char *virtual_root; 171 char *virtual_root;
171 int cache_size; 172 int cache_size;
172 int cache_dynamic_ttl; 173 int cache_dynamic_ttl;
173 int cache_max_create_time; 174 int cache_max_create_time;
174 int cache_repo_ttl; 175 int cache_repo_ttl;
175 int cache_root_ttl; 176 int cache_root_ttl;
176 int cache_scanrc_ttl; 177 int cache_scanrc_ttl;
177 int cache_static_ttl; 178 int cache_static_ttl;
178 int embedded; 179 int embedded;
179 int enable_filter_overrides; 180 int enable_filter_overrides;
180 int enable_index_links; 181 int enable_index_links;
181 int enable_log_filecount; 182 int enable_log_filecount;
182 int enable_log_linecount; 183 int enable_log_linecount;
183 int enable_remote_branches; 184 int enable_remote_branches;
185 int enable_subject_links;
184 int enable_tree_linenumbers; 186 int enable_tree_linenumbers;
185 int local_time; 187 int local_time;
186 int max_repo_count; 188 int max_repo_count;
187 int max_commit_count; 189 int max_commit_count;
188 int max_lock_attempts; 190 int max_lock_attempts;
189 int max_msg_len; 191 int max_msg_len;
190 int max_repodesc_len; 192 int max_repodesc_len;
191 int max_blob_size; 193 int max_blob_size;
192 int max_stats; 194 int max_stats;
193 int nocache; 195 int nocache;
194 int noplainemail; 196 int noplainemail;
195 int noheader; 197 int noheader;
196 int renamelimit; 198 int renamelimit;
197 int snapshots; 199 int snapshots;
198 int summary_branches; 200 int summary_branches;
199 int summary_log; 201 int summary_log;
200 int summary_tags; 202 int summary_tags;
201 int ssdiff; 203 int ssdiff;
202 struct string_list mimetypes; 204 struct string_list mimetypes;
203 struct cgit_filter *about_filter; 205 struct cgit_filter *about_filter;
204 struct cgit_filter *commit_filter; 206 struct cgit_filter *commit_filter;
205 struct cgit_filter *source_filter; 207 struct cgit_filter *source_filter;
206}; 208};
207 209
208struct cgit_page { 210struct cgit_page {
209 time_t modified; 211 time_t modified;
210 time_t expires; 212 time_t expires;
211 size_t size; 213 size_t size;
212 char *mimetype; 214 char *mimetype;
213 char *charset; 215 char *charset;
214 char *filename; 216 char *filename;
215 char *etag; 217 char *etag;
216 char *title; 218 char *title;
217 int status; 219 int status;
218 char *statusmsg; 220 char *statusmsg;
219}; 221};
220 222
221struct cgit_environment { 223struct cgit_environment {
222 char *cgit_config; 224 char *cgit_config;
223 char *http_host; 225 char *http_host;
224 char *https; 226 char *https;
225 char *no_http; 227 char *no_http;
226 char *path_info; 228 char *path_info;
227 char *query_string; 229 char *query_string;
228 char *request_method; 230 char *request_method;
229 char *script_name; 231 char *script_name;
230 char *server_name; 232 char *server_name;
231 char *server_port; 233 char *server_port;
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index d74d9e7..fcd4308 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -70,96 +70,102 @@ cache-static-ttl::
70 version of repository pages accessed with a fixed SHA1. Default value: 70 version of repository pages accessed with a fixed SHA1. Default value:
71 "5". 71 "5".
72 72
73clone-prefix:: 73clone-prefix::
74 Space-separated list of common prefixes which, when combined with a 74 Space-separated list of common prefixes which, when combined with a
75 repository url, generates valid clone urls for the repository. This 75 repository url, generates valid clone urls for the repository. This
76 setting is only used if `repo.clone-url` is unspecified. Default value: 76 setting is only used if `repo.clone-url` is unspecified. Default value:
77 none. 77 none.
78 78
79commit-filter:: 79commit-filter::
80 Specifies a command which will be invoked to format commit messages. 80 Specifies a command which will be invoked to format commit messages.
81 The command will get the message on its STDIN, and the STDOUT from the 81 The command will get the message on its STDIN, and the STDOUT from the
82 command will be included verbatim as the commit message, i.e. this can 82 command will be included verbatim as the commit message, i.e. this can
83 be used to implement bugtracker integration. Default value: none. 83 be used to implement bugtracker integration. Default value: none.
84 84
85css:: 85css::
86 Url which specifies the css document to include in all cgit pages. 86 Url which specifies the css document to include in all cgit pages.
87 Default value: "/cgit.css". 87 Default value: "/cgit.css".
88 88
89embedded:: 89embedded::
90 Flag which, when set to "1", will make cgit generate a html fragment 90 Flag which, when set to "1", will make cgit generate a html fragment
91 suitable for embedding in other html pages. Default value: none. See 91 suitable for embedding in other html pages. Default value: none. See
92 also: "noheader". 92 also: "noheader".
93 93
94enable-filter-overrides:: 94enable-filter-overrides::
95 Flag which, when set to "1", allows all filter settings to be 95 Flag which, when set to "1", allows all filter settings to be
96 overridden in repository-specific cgitrc files. Default value: none. 96 overridden in repository-specific cgitrc files. Default value: none.
97 97
98enable-index-links:: 98enable-index-links::
99 Flag which, when set to "1", will make cgit generate extra links for 99 Flag which, when set to "1", will make cgit generate extra links for
100 each repo in the repository index (specifically, to the "summary", 100 each repo in the repository index (specifically, to the "summary",
101 "commit" and "tree" pages). Default value: "0". 101 "commit" and "tree" pages). Default value: "0".
102 102
103enable-log-filecount:: 103enable-log-filecount::
104 Flag which, when set to "1", will make cgit print the number of 104 Flag which, when set to "1", will make cgit print the number of
105 modified files for each commit on the repository log page. Default 105 modified files for each commit on the repository log page. Default
106 value: "0". 106 value: "0".
107 107
108enable-log-linecount:: 108enable-log-linecount::
109 Flag which, when set to "1", will make cgit print the number of added 109 Flag which, when set to "1", will make cgit print the number of added
110 and removed lines for each commit on the repository log page. Default 110 and removed lines for each commit on the repository log page. Default
111 value: "0". 111 value: "0".
112 112
113enable-remote-branches:: 113enable-remote-branches::
114 Flag which, when set to "1", will make cgit display remote branches 114 Flag which, when set to "1", will make cgit display remote branches
115 in the summary and refs views. Default value: "0". See also: 115 in the summary and refs views. Default value: "0". See also:
116 "repo.enable-remote-branches". 116 "repo.enable-remote-branches".
117 117
118enable-subject-links::
119 Flag which, when set to "1", will make cgit use the subject of the
120 parent commit as link text when generating links to parent commits
121 in commit view. Default value: "0". See also:
122 "repo.enable-subject-links".
123
118enable-tree-linenumbers:: 124enable-tree-linenumbers::
119 Flag which, when set to "1", will make cgit generate linenumber links 125 Flag which, when set to "1", will make cgit generate linenumber links
120 for plaintext blobs printed in the tree view. Default value: "1". 126 for plaintext blobs printed in the tree view. Default value: "1".
121 127
122favicon:: 128favicon::
123 Url used as link to a shortcut icon for cgit. If specified, it is 129 Url used as link to a shortcut icon for cgit. If specified, it is
124 suggested to use the value "/favicon.ico" since certain browsers will 130 suggested to use the value "/favicon.ico" since certain browsers will
125 ignore other values. Default value: none. 131 ignore other values. Default value: none.
126 132
127footer:: 133footer::
128 The content of the file specified with this option will be included 134 The content of the file specified with this option will be included
129 verbatim at the bottom of all pages (i.e. it replaces the standard 135 verbatim at the bottom of all pages (i.e. it replaces the standard
130 "generated by..." message. Default value: none. 136 "generated by..." message. Default value: none.
131 137
132head-include:: 138head-include::
133 The content of the file specified with this option will be included 139 The content of the file specified with this option will be included
134 verbatim in the html HEAD section on all pages. Default value: none. 140 verbatim in the html HEAD section on all pages. Default value: none.
135 141
136header:: 142header::
137 The content of the file specified with this option will be included 143 The content of the file specified with this option will be included
138 verbatim at the top of all pages. Default value: none. 144 verbatim at the top of all pages. Default value: none.
139 145
140include:: 146include::
141 Name of a configfile to include before the rest of the current config- 147 Name of a configfile to include before the rest of the current config-
142 file is parsed. Default value: none. 148 file is parsed. Default value: none.
143 149
144index-header:: 150index-header::
145 The content of the file specified with this option will be included 151 The content of the file specified with this option will be included
146 verbatim above the repository index. This setting is deprecated, and 152 verbatim above the repository index. This setting is deprecated, and
147 will not be supported by cgit-1.0 (use root-readme instead). Default 153 will not be supported by cgit-1.0 (use root-readme instead). Default
148 value: none. 154 value: none.
149 155
150index-info:: 156index-info::
151 The content of the file specified with this option will be included 157 The content of the file specified with this option will be included
152 verbatim below the heading on the repository index page. This setting 158 verbatim below the heading on the repository index page. This setting
153 is deprecated, and will not be supported by cgit-1.0 (use root-desc 159 is deprecated, and will not be supported by cgit-1.0 (use root-desc
154 instead). Default value: none. 160 instead). Default value: none.
155 161
156local-time:: 162local-time::
157 Flag which, if set to "1", makes cgit print commit and tag times in the 163 Flag which, if set to "1", makes cgit print commit and tag times in the
158 servers timezone. Default value: "0". 164 servers timezone. Default value: "0".
159 165
160logo:: 166logo::
161 Url which specifies the source of an image which will be used as a logo 167 Url which specifies the source of an image which will be used as a logo
162 on all cgit pages. Default value: "/cgit.png". 168 on all cgit pages. Default value: "/cgit.png".
163 169
164logo-link:: 170logo-link::
165 Url loaded when clicking on the cgit logo image. If unspecified the 171 Url loaded when clicking on the cgit logo image. If unspecified the
@@ -276,96 +282,100 @@ summary-log::
276 "summary" view. Default value: "10". 282 "summary" view. Default value: "10".
277 283
278summary-tags:: 284summary-tags::
279 Specifies the number of tags to display in the repository "summary" 285 Specifies the number of tags to display in the repository "summary"
280 view. Default value: "10". 286 view. Default value: "10".
281 287
282virtual-root:: 288virtual-root::
283 Url which, if specified, will be used as root for all cgit links. It 289 Url which, if specified, will be used as root for all cgit links. It
284 will also cause cgit to generate 'virtual urls', i.e. urls like 290 will also cause cgit to generate 'virtual urls', i.e. urls like
285 '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default 291 '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default
286 value: none. 292 value: none.
287 NOTE: cgit has recently learned how to use PATH_INFO to achieve the 293 NOTE: cgit has recently learned how to use PATH_INFO to achieve the
288 same kind of virtual urls, so this option will probably be deprecated. 294 same kind of virtual urls, so this option will probably be deprecated.
289 295
290REPOSITORY SETTINGS 296REPOSITORY SETTINGS
291------------------- 297-------------------
292repo.about-filter:: 298repo.about-filter::
293 Override the default about-filter. Default value: none. See also: 299 Override the default about-filter. Default value: none. See also:
294 "enable-filter-overrides". 300 "enable-filter-overrides".
295 301
296repo.clone-url:: 302repo.clone-url::
297 A list of space-separated urls which can be used to clone this repo. 303 A list of space-separated urls which can be used to clone this repo.
298 Default value: none. 304 Default value: none.
299 305
300repo.commit-filter:: 306repo.commit-filter::
301 Override the default commit-filter. Default value: none. See also: 307 Override the default commit-filter. Default value: none. See also:
302 "enable-filter-overrides". 308 "enable-filter-overrides".
303 309
304repo.defbranch:: 310repo.defbranch::
305 The name of the default branch for this repository. If no such branch 311 The name of the default branch for this repository. If no such branch
306 exists in the repository, the first branch name (when sorted) is used 312 exists in the repository, the first branch name (when sorted) is used
307 as default instead. Default value: "master". 313 as default instead. Default value: "master".
308 314
309repo.desc:: 315repo.desc::
310 The value to show as repository description. Default value: none. 316 The value to show as repository description. Default value: none.
311 317
312repo.enable-log-filecount:: 318repo.enable-log-filecount::
313 A flag which can be used to disable the global setting 319 A flag which can be used to disable the global setting
314 `enable-log-filecount'. Default value: none. 320 `enable-log-filecount'. Default value: none.
315 321
316repo.enable-log-linecount:: 322repo.enable-log-linecount::
317 A flag which can be used to disable the global setting 323 A flag which can be used to disable the global setting
318 `enable-log-linecount'. Default value: none. 324 `enable-log-linecount'. Default value: none.
319 325
320repo.enable-remote-branches:: 326repo.enable-remote-branches::
321 Flag which, when set to "1", will make cgit display remote branches 327 Flag which, when set to "1", will make cgit display remote branches
322 in the summary and refs views. Default value: <enable-remote-branches>. 328 in the summary and refs views. Default value: <enable-remote-branches>.
323 329
330repo.enable-subject-links::
331 A flag which can be used to override the global setting
332 `enable-subject-links'. Default value: none.
333
324repo.max-stats:: 334repo.max-stats::
325 Override the default maximum statistics period. Valid values are equal 335 Override the default maximum statistics period. Valid values are equal
326 to the values specified for the global "max-stats" setting. Default 336 to the values specified for the global "max-stats" setting. Default
327 value: none. 337 value: none.
328 338
329repo.name:: 339repo.name::
330 The value to show as repository name. Default value: <repo.url>. 340 The value to show as repository name. Default value: <repo.url>.
331 341
332repo.owner:: 342repo.owner::
333 A value used to identify the owner of the repository. Default value: 343 A value used to identify the owner of the repository. Default value:
334 none. 344 none.
335 345
336repo.path:: 346repo.path::
337 An absolute path to the repository directory. For non-bare repositories 347 An absolute path to the repository directory. For non-bare repositories
338 this is the .git-directory. Default value: none. 348 this is the .git-directory. Default value: none.
339 349
340repo.readme:: 350repo.readme::
341 A path (relative to <repo.path>) which specifies a file to include 351 A path (relative to <repo.path>) which specifies a file to include
342 verbatim as the "About" page for this repo. Default value: none. 352 verbatim as the "About" page for this repo. Default value: none.
343 353
344repo.snapshots:: 354repo.snapshots::
345 A mask of allowed snapshot-formats for this repo, restricted by the 355 A mask of allowed snapshot-formats for this repo, restricted by the
346 "snapshots" global setting. Default value: <snapshots>. 356 "snapshots" global setting. Default value: <snapshots>.
347 357
348repo.section:: 358repo.section::
349 Override the current section name for this repository. Default value: 359 Override the current section name for this repository. Default value:
350 none. 360 none.
351 361
352repo.source-filter:: 362repo.source-filter::
353 Override the default source-filter. Default value: none. See also: 363 Override the default source-filter. Default value: none. See also:
354 "enable-filter-overrides". 364 "enable-filter-overrides".
355 365
356repo.url:: 366repo.url::
357 The relative url used to access the repository. This must be the first 367 The relative url used to access the repository. This must be the first
358 setting specified for each repo. Default value: none. 368 setting specified for each repo. Default value: none.
359 369
360 370
361REPOSITORY-SPECIFIC CGITRC FILE 371REPOSITORY-SPECIFIC CGITRC FILE
362------------------------------- 372-------------------------------
363When the option "scan-path" is used to auto-discover git repositories, cgit 373When the option "scan-path" is used to auto-discover git repositories, cgit
364will try to parse the file "cgitrc" within any found repository. Such a 374will try to parse the file "cgitrc" within any found repository. Such a
365repo-specific config file may contain any of the repo-specific options 375repo-specific config file may contain any of the repo-specific options
366described above, except "repo.url" and "repo.path". Additionally, the "filter" 376described above, except "repo.url" and "repo.path". Additionally, the "filter"
367options are only acknowledged in repo-specific config files when 377options are only acknowledged in repo-specific config files when
368"enable-filter-overrides" is set to "1". 378"enable-filter-overrides" is set to "1".
369 379
370Note: the "repo." prefix is dropped from the option names in repo-specific 380Note: the "repo." prefix is dropped from the option names in repo-specific
371config files, e.g. "repo.desc" becomes "desc". 381config files, e.g. "repo.desc" becomes "desc".
diff --git a/shared.c b/shared.c
index 83b71e6..8b3a045 100644
--- a/shared.c
+++ b/shared.c
@@ -15,96 +15,97 @@ int cgit_cmd;
15int chk_zero(int result, char *msg) 15int chk_zero(int result, char *msg)
16{ 16{
17 if (result != 0) 17 if (result != 0)
18 die("%s: %s", msg, strerror(errno)); 18 die("%s: %s", msg, strerror(errno));
19 return result; 19 return result;
20} 20}
21 21
22int chk_positive(int result, char *msg) 22int chk_positive(int result, char *msg)
23{ 23{
24 if (result <= 0) 24 if (result <= 0)
25 die("%s: %s", msg, strerror(errno)); 25 die("%s: %s", msg, strerror(errno));
26 return result; 26 return result;
27} 27}
28 28
29int chk_non_negative(int result, char *msg) 29int chk_non_negative(int result, char *msg)
30{ 30{
31 if (result < 0) 31 if (result < 0)
32 die("%s: %s",msg, strerror(errno)); 32 die("%s: %s",msg, strerror(errno));
33 return result; 33 return result;
34} 34}
35 35
36struct cgit_repo *cgit_add_repo(const char *url) 36struct cgit_repo *cgit_add_repo(const char *url)
37{ 37{
38 struct cgit_repo *ret; 38 struct cgit_repo *ret;
39 39
40 if (++cgit_repolist.count > cgit_repolist.length) { 40 if (++cgit_repolist.count > cgit_repolist.length) {
41 if (cgit_repolist.length == 0) 41 if (cgit_repolist.length == 0)
42 cgit_repolist.length = 8; 42 cgit_repolist.length = 8;
43 else 43 else
44 cgit_repolist.length *= 2; 44 cgit_repolist.length *= 2;
45 cgit_repolist.repos = xrealloc(cgit_repolist.repos, 45 cgit_repolist.repos = xrealloc(cgit_repolist.repos,
46 cgit_repolist.length * 46 cgit_repolist.length *
47 sizeof(struct cgit_repo)); 47 sizeof(struct cgit_repo));
48 } 48 }
49 49
50 ret = &cgit_repolist.repos[cgit_repolist.count-1]; 50 ret = &cgit_repolist.repos[cgit_repolist.count-1];
51 memset(ret, 0, sizeof(struct cgit_repo)); 51 memset(ret, 0, sizeof(struct cgit_repo));
52 ret->url = trim_end(url, '/'); 52 ret->url = trim_end(url, '/');
53 ret->name = ret->url; 53 ret->name = ret->url;
54 ret->path = NULL; 54 ret->path = NULL;
55 ret->desc = "[no description]"; 55 ret->desc = "[no description]";
56 ret->owner = NULL; 56 ret->owner = NULL;
57 ret->section = ctx.cfg.section; 57 ret->section = ctx.cfg.section;
58 ret->defbranch = "master"; 58 ret->defbranch = "master";
59 ret->snapshots = ctx.cfg.snapshots; 59 ret->snapshots = ctx.cfg.snapshots;
60 ret->enable_log_filecount = ctx.cfg.enable_log_filecount; 60 ret->enable_log_filecount = ctx.cfg.enable_log_filecount;
61 ret->enable_log_linecount = ctx.cfg.enable_log_linecount; 61 ret->enable_log_linecount = ctx.cfg.enable_log_linecount;
62 ret->enable_remote_branches = ctx.cfg.enable_remote_branches; 62 ret->enable_remote_branches = ctx.cfg.enable_remote_branches;
63 ret->enable_subject_links = ctx.cfg.enable_subject_links;
63 ret->max_stats = ctx.cfg.max_stats; 64 ret->max_stats = ctx.cfg.max_stats;
64 ret->module_link = ctx.cfg.module_link; 65 ret->module_link = ctx.cfg.module_link;
65 ret->readme = NULL; 66 ret->readme = NULL;
66 ret->mtime = -1; 67 ret->mtime = -1;
67 ret->about_filter = ctx.cfg.about_filter; 68 ret->about_filter = ctx.cfg.about_filter;
68 ret->commit_filter = ctx.cfg.commit_filter; 69 ret->commit_filter = ctx.cfg.commit_filter;
69 ret->source_filter = ctx.cfg.source_filter; 70 ret->source_filter = ctx.cfg.source_filter;
70 return ret; 71 return ret;
71} 72}
72 73
73struct cgit_repo *cgit_get_repoinfo(const char *url) 74struct cgit_repo *cgit_get_repoinfo(const char *url)
74{ 75{
75 int i; 76 int i;
76 struct cgit_repo *repo; 77 struct cgit_repo *repo;
77 78
78 for (i=0; i<cgit_repolist.count; i++) { 79 for (i=0; i<cgit_repolist.count; i++) {
79 repo = &cgit_repolist.repos[i]; 80 repo = &cgit_repolist.repos[i];
80 if (!strcmp(repo->url, url)) 81 if (!strcmp(repo->url, url))
81 return repo; 82 return repo;
82 } 83 }
83 return NULL; 84 return NULL;
84} 85}
85 86
86void *cgit_free_commitinfo(struct commitinfo *info) 87void *cgit_free_commitinfo(struct commitinfo *info)
87{ 88{
88 free(info->author); 89 free(info->author);
89 free(info->author_email); 90 free(info->author_email);
90 free(info->committer); 91 free(info->committer);
91 free(info->committer_email); 92 free(info->committer_email);
92 free(info->subject); 93 free(info->subject);
93 free(info->msg); 94 free(info->msg);
94 free(info->msg_encoding); 95 free(info->msg_encoding);
95 free(info); 96 free(info);
96 return NULL; 97 return NULL;
97} 98}
98 99
99char *trim_end(const char *str, char c) 100char *trim_end(const char *str, char c)
100{ 101{
101 int len; 102 int len;
102 char *s, *t; 103 char *s, *t;
103 104
104 if (str == NULL) 105 if (str == NULL)
105 return NULL; 106 return NULL;
106 t = (char *)str; 107 t = (char *)str;
107 len = strlen(t); 108 len = strlen(t);
108 while(len > 0 && t[len - 1] == c) 109 while(len > 0 && t[len - 1] == c)
109 len--; 110 len--;
110 111
diff --git a/ui-commit.c b/ui-commit.c
index b5e3c01..41313b9 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -1,123 +1,127 @@
1/* ui-commit.c: generate commit view 1/* ui-commit.c: generate commit view
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include "html.h" 10#include "html.h"
11#include "ui-shared.h" 11#include "ui-shared.h"
12#include "ui-diff.h" 12#include "ui-diff.h"
13#include "ui-log.h" 13#include "ui-log.h"
14 14
15void cgit_print_commit(char *hex) 15void cgit_print_commit(char *hex)
16{ 16{
17 struct commit *commit, *parent; 17 struct commit *commit, *parent;
18 struct commitinfo *info; 18 struct commitinfo *info, *parent_info;
19 struct commit_list *p; 19 struct commit_list *p;
20 unsigned char sha1[20]; 20 unsigned char sha1[20];
21 char *tmp; 21 char *tmp, *tmp2;
22 int parents = 0; 22 int parents = 0;
23 23
24 if (!hex) 24 if (!hex)
25 hex = ctx.qry.head; 25 hex = ctx.qry.head;
26 26
27 if (get_sha1(hex, sha1)) { 27 if (get_sha1(hex, sha1)) {
28 cgit_print_error(fmt("Bad object id: %s", hex)); 28 cgit_print_error(fmt("Bad object id: %s", hex));
29 return; 29 return;
30 } 30 }
31 commit = lookup_commit_reference(sha1); 31 commit = lookup_commit_reference(sha1);
32 if (!commit) { 32 if (!commit) {
33 cgit_print_error(fmt("Bad commit reference: %s", hex)); 33 cgit_print_error(fmt("Bad commit reference: %s", hex));
34 return; 34 return;
35 } 35 }
36 info = cgit_parse_commit(commit); 36 info = cgit_parse_commit(commit);
37 37
38 load_ref_decorations(DECORATE_FULL_REFS); 38 load_ref_decorations(DECORATE_FULL_REFS);
39 39
40 html("<table summary='commit info' class='commit-info'>\n"); 40 html("<table summary='commit info' class='commit-info'>\n");
41 html("<tr><th>author</th><td>"); 41 html("<tr><th>author</th><td>");
42 html_txt(info->author); 42 html_txt(info->author);
43 if (!ctx.cfg.noplainemail) { 43 if (!ctx.cfg.noplainemail) {
44 html(" "); 44 html(" ");
45 html_txt(info->author_email); 45 html_txt(info->author_email);
46 } 46 }
47 html("</td><td class='right'>"); 47 html("</td><td class='right'>");
48 cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time); 48 cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time);
49 html("</td></tr>\n"); 49 html("</td></tr>\n");
50 html("<tr><th>committer</th><td>"); 50 html("<tr><th>committer</th><td>");
51 html_txt(info->committer); 51 html_txt(info->committer);
52 if (!ctx.cfg.noplainemail) { 52 if (!ctx.cfg.noplainemail) {
53 html(" "); 53 html(" ");
54 html_txt(info->committer_email); 54 html_txt(info->committer_email);
55 } 55 }
56 html("</td><td class='right'>"); 56 html("</td><td class='right'>");
57 cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time); 57 cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time);
58 html("</td></tr>\n"); 58 html("</td></tr>\n");
59 html("<tr><th>commit</th><td colspan='2' class='sha1'>"); 59 html("<tr><th>commit</th><td colspan='2' class='sha1'>");
60 tmp = sha1_to_hex(commit->object.sha1); 60 tmp = sha1_to_hex(commit->object.sha1);
61 cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp, 0); 61 cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp, 0);
62 html(" ("); 62 html(" (");
63 cgit_patch_link("patch", NULL, NULL, NULL, tmp); 63 cgit_patch_link("patch", NULL, NULL, NULL, tmp);
64 html(") ("); 64 html(") (");
65 if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff)) 65 if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff))
66 cgit_commit_link("unidiff", NULL, NULL, ctx.qry.head, tmp, 1); 66 cgit_commit_link("unidiff", NULL, NULL, ctx.qry.head, tmp, 1);
67 else 67 else
68 cgit_commit_link("side-by-side diff", NULL, NULL, ctx.qry.head, tmp, 1); 68 cgit_commit_link("side-by-side diff", NULL, NULL, ctx.qry.head, tmp, 1);
69 html(")</td></tr>\n"); 69 html(")</td></tr>\n");
70 html("<tr><th>tree</th><td colspan='2' class='sha1'>"); 70 html("<tr><th>tree</th><td colspan='2' class='sha1'>");
71 tmp = xstrdup(hex); 71 tmp = xstrdup(hex);
72 cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL, 72 cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL,
73 ctx.qry.head, tmp, NULL); 73 ctx.qry.head, tmp, NULL);
74 html("</td></tr>\n"); 74 html("</td></tr>\n");
75 for (p = commit->parents; p ; p = p->next) { 75 for (p = commit->parents; p ; p = p->next) {
76 parent = lookup_commit_reference(p->item->object.sha1); 76 parent = lookup_commit_reference(p->item->object.sha1);
77 if (!parent) { 77 if (!parent) {
78 html("<tr><td colspan='3'>"); 78 html("<tr><td colspan='3'>");
79 cgit_print_error("Error reading parent commit"); 79 cgit_print_error("Error reading parent commit");
80 html("</td></tr>"); 80 html("</td></tr>");
81 continue; 81 continue;
82 } 82 }
83 html("<tr><th>parent</th>" 83 html("<tr><th>parent</th>"
84 "<td colspan='2' class='sha1'>"); 84 "<td colspan='2' class='sha1'>");
85 cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, 85 tmp = tmp2 = sha1_to_hex(p->item->object.sha1);
86 ctx.qry.head, sha1_to_hex(p->item->object.sha1), 0); 86 if (ctx.repo->enable_subject_links) {
87 parent_info = cgit_parse_commit(parent);
88 tmp2 = parent_info->subject;
89 }
90 cgit_commit_link(tmp2, NULL, NULL, ctx.qry.head, tmp, 0);
87 html(" ("); 91 html(" (");
88 cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, 92 cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex,
89 sha1_to_hex(p->item->object.sha1), NULL, 0); 93 sha1_to_hex(p->item->object.sha1), NULL, 0);
90 html(")</td></tr>"); 94 html(")</td></tr>");
91 parents++; 95 parents++;
92 } 96 }
93 if (ctx.repo->snapshots) { 97 if (ctx.repo->snapshots) {
94 html("<tr><th>download</th><td colspan='2' class='sha1'>"); 98 html("<tr><th>download</th><td colspan='2' class='sha1'>");
95 cgit_print_snapshot_links(ctx.qry.repo, ctx.qry.head, 99 cgit_print_snapshot_links(ctx.qry.repo, ctx.qry.head,
96 hex, ctx.repo->snapshots); 100 hex, ctx.repo->snapshots);
97 html("</td></tr>"); 101 html("</td></tr>");
98 } 102 }
99 html("</table>\n"); 103 html("</table>\n");
100 html("<div class='commit-subject'>"); 104 html("<div class='commit-subject'>");
101 if (ctx.repo->commit_filter) 105 if (ctx.repo->commit_filter)
102 cgit_open_filter(ctx.repo->commit_filter); 106 cgit_open_filter(ctx.repo->commit_filter);
103 html_txt(info->subject); 107 html_txt(info->subject);
104 if (ctx.repo->commit_filter) 108 if (ctx.repo->commit_filter)
105 cgit_close_filter(ctx.repo->commit_filter); 109 cgit_close_filter(ctx.repo->commit_filter);
106 show_commit_decorations(commit); 110 show_commit_decorations(commit);
107 html("</div>"); 111 html("</div>");
108 html("<div class='commit-msg'>"); 112 html("<div class='commit-msg'>");
109 if (ctx.repo->commit_filter) 113 if (ctx.repo->commit_filter)
110 cgit_open_filter(ctx.repo->commit_filter); 114 cgit_open_filter(ctx.repo->commit_filter);
111 html_txt(info->msg); 115 html_txt(info->msg);
112 if (ctx.repo->commit_filter) 116 if (ctx.repo->commit_filter)
113 cgit_close_filter(ctx.repo->commit_filter); 117 cgit_close_filter(ctx.repo->commit_filter);
114 html("</div>"); 118 html("</div>");
115 if (parents < 3) { 119 if (parents < 3) {
116 if (parents) 120 if (parents)
117 tmp = sha1_to_hex(commit->parents->item->object.sha1); 121 tmp = sha1_to_hex(commit->parents->item->object.sha1);
118 else 122 else
119 tmp = NULL; 123 tmp = NULL;
120 cgit_print_diff(ctx.qry.sha1, tmp, NULL); 124 cgit_print_diff(ctx.qry.sha1, tmp, NULL);
121 } 125 }
122 cgit_free_commitinfo(info); 126 cgit_free_commitinfo(info);
123} 127}