author | Lars Hjemli <hjemli@gmail.com> | 2008-11-29 17:39:41 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2008-11-29 17:39:41 (UTC) |
commit | 0274b57d55a12ed38259757dbfae96b79cfa2e0b (patch) (unidiff) | |
tree | 34c7204f88168f791ef48f603bb8ab66e9df523c | |
parent | 7b5cee65fd9cf31e4f19ce4ff613778cb95512a9 (diff) | |
download | cgit-0274b57d55a12ed38259757dbfae96b79cfa2e0b.zip cgit-0274b57d55a12ed38259757dbfae96b79cfa2e0b.tar.gz cgit-0274b57d55a12ed38259757dbfae96b79cfa2e0b.tar.bz2 |
ui-log: add support for showing the full commit message
Some users prefer to see the full message, so to make these users happy
the new querystring parameter "showmsg" can be used to print the full
commit message per log entry.
A link is provided in the log heading to make this function accessible,
and all links and forms tries to preserve the users preference.
Note: the new link is not displayed on the summary page since the point
of the summary page is to be a summary, but it is still obeyed if specified
manually.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | cgit.c | 2 | ||||
-rw-r--r-- | cgit.h | 1 | ||||
-rw-r--r-- | ui-log.c | 32 | ||||
-rw-r--r-- | ui-refs.c | 3 | ||||
-rw-r--r-- | ui-repolist.c | 2 | ||||
-rw-r--r-- | ui-shared.c | 12 | ||||
-rw-r--r-- | ui-shared.h | 2 | ||||
-rw-r--r-- | ui-tree.c | 2 |
8 files changed, 45 insertions, 11 deletions
@@ -61,192 +61,194 @@ void config_cb(const char *name, const char *value) | |||
61 | else if (!strcmp(name, "cache-root-ttl")) | 61 | else if (!strcmp(name, "cache-root-ttl")) |
62 | ctx.cfg.cache_root_ttl = atoi(value); | 62 | ctx.cfg.cache_root_ttl = atoi(value); |
63 | else if (!strcmp(name, "cache-repo-ttl")) | 63 | else if (!strcmp(name, "cache-repo-ttl")) |
64 | ctx.cfg.cache_repo_ttl = atoi(value); | 64 | ctx.cfg.cache_repo_ttl = atoi(value); |
65 | else if (!strcmp(name, "cache-static-ttl")) | 65 | else if (!strcmp(name, "cache-static-ttl")) |
66 | ctx.cfg.cache_static_ttl = atoi(value); | 66 | ctx.cfg.cache_static_ttl = atoi(value); |
67 | else if (!strcmp(name, "cache-dynamic-ttl")) | 67 | else if (!strcmp(name, "cache-dynamic-ttl")) |
68 | ctx.cfg.cache_dynamic_ttl = atoi(value); | 68 | ctx.cfg.cache_dynamic_ttl = atoi(value); |
69 | else if (!strcmp(name, "max-message-length")) | 69 | else if (!strcmp(name, "max-message-length")) |
70 | ctx.cfg.max_msg_len = atoi(value); | 70 | ctx.cfg.max_msg_len = atoi(value); |
71 | else if (!strcmp(name, "max-repodesc-length")) | 71 | else if (!strcmp(name, "max-repodesc-length")) |
72 | ctx.cfg.max_repodesc_len = atoi(value); | 72 | ctx.cfg.max_repodesc_len = atoi(value); |
73 | else if (!strcmp(name, "max-repo-count")) | 73 | else if (!strcmp(name, "max-repo-count")) |
74 | ctx.cfg.max_repo_count = atoi(value); | 74 | ctx.cfg.max_repo_count = atoi(value); |
75 | else if (!strcmp(name, "max-commit-count")) | 75 | else if (!strcmp(name, "max-commit-count")) |
76 | ctx.cfg.max_commit_count = atoi(value); | 76 | ctx.cfg.max_commit_count = atoi(value); |
77 | else if (!strcmp(name, "summary-log")) | 77 | else if (!strcmp(name, "summary-log")) |
78 | ctx.cfg.summary_log = atoi(value); | 78 | ctx.cfg.summary_log = atoi(value); |
79 | else if (!strcmp(name, "summary-branches")) | 79 | else if (!strcmp(name, "summary-branches")) |
80 | ctx.cfg.summary_branches = atoi(value); | 80 | ctx.cfg.summary_branches = atoi(value); |
81 | else if (!strcmp(name, "summary-tags")) | 81 | else if (!strcmp(name, "summary-tags")) |
82 | ctx.cfg.summary_tags = atoi(value); | 82 | ctx.cfg.summary_tags = atoi(value); |
83 | else if (!strcmp(name, "agefile")) | 83 | else if (!strcmp(name, "agefile")) |
84 | ctx.cfg.agefile = xstrdup(value); | 84 | ctx.cfg.agefile = xstrdup(value); |
85 | else if (!strcmp(name, "renamelimit")) | 85 | else if (!strcmp(name, "renamelimit")) |
86 | ctx.cfg.renamelimit = atoi(value); | 86 | ctx.cfg.renamelimit = atoi(value); |
87 | else if (!strcmp(name, "robots")) | 87 | else if (!strcmp(name, "robots")) |
88 | ctx.cfg.robots = xstrdup(value); | 88 | ctx.cfg.robots = xstrdup(value); |
89 | else if (!strcmp(name, "clone-prefix")) | 89 | else if (!strcmp(name, "clone-prefix")) |
90 | ctx.cfg.clone_prefix = xstrdup(value); | 90 | ctx.cfg.clone_prefix = xstrdup(value); |
91 | else if (!strcmp(name, "local-time")) | 91 | else if (!strcmp(name, "local-time")) |
92 | ctx.cfg.local_time = atoi(value); | 92 | ctx.cfg.local_time = atoi(value); |
93 | else if (!strcmp(name, "repo.group")) | 93 | else if (!strcmp(name, "repo.group")) |
94 | ctx.cfg.repo_group = xstrdup(value); | 94 | ctx.cfg.repo_group = xstrdup(value); |
95 | else if (!strcmp(name, "repo.url")) | 95 | else if (!strcmp(name, "repo.url")) |
96 | ctx.repo = cgit_add_repo(value); | 96 | ctx.repo = cgit_add_repo(value); |
97 | else if (!strcmp(name, "repo.name")) | 97 | else if (!strcmp(name, "repo.name")) |
98 | ctx.repo->name = xstrdup(value); | 98 | ctx.repo->name = xstrdup(value); |
99 | else if (ctx.repo && !strcmp(name, "repo.path")) | 99 | else if (ctx.repo && !strcmp(name, "repo.path")) |
100 | ctx.repo->path = trim_end(value, '/'); | 100 | ctx.repo->path = trim_end(value, '/'); |
101 | else if (ctx.repo && !strcmp(name, "repo.clone-url")) | 101 | else if (ctx.repo && !strcmp(name, "repo.clone-url")) |
102 | ctx.repo->clone_url = xstrdup(value); | 102 | ctx.repo->clone_url = xstrdup(value); |
103 | else if (ctx.repo && !strcmp(name, "repo.desc")) | 103 | else if (ctx.repo && !strcmp(name, "repo.desc")) |
104 | ctx.repo->desc = xstrdup(value); | 104 | ctx.repo->desc = xstrdup(value); |
105 | else if (ctx.repo && !strcmp(name, "repo.owner")) | 105 | else if (ctx.repo && !strcmp(name, "repo.owner")) |
106 | ctx.repo->owner = xstrdup(value); | 106 | ctx.repo->owner = xstrdup(value); |
107 | else if (ctx.repo && !strcmp(name, "repo.defbranch")) | 107 | else if (ctx.repo && !strcmp(name, "repo.defbranch")) |
108 | ctx.repo->defbranch = xstrdup(value); | 108 | ctx.repo->defbranch = xstrdup(value); |
109 | else if (ctx.repo && !strcmp(name, "repo.snapshots")) | 109 | else if (ctx.repo && !strcmp(name, "repo.snapshots")) |
110 | ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ | 110 | ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ |
111 | else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) | 111 | else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) |
112 | ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); | 112 | ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); |
113 | else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) | 113 | else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) |
114 | ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); | 114 | ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); |
115 | else if (ctx.repo && !strcmp(name, "repo.module-link")) | 115 | else if (ctx.repo && !strcmp(name, "repo.module-link")) |
116 | ctx.repo->module_link= xstrdup(value); | 116 | ctx.repo->module_link= xstrdup(value); |
117 | else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { | 117 | else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { |
118 | if (*value == '/') | 118 | if (*value == '/') |
119 | ctx.repo->readme = xstrdup(value); | 119 | ctx.repo->readme = xstrdup(value); |
120 | else | 120 | else |
121 | ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); | 121 | ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); |
122 | } else if (!strcmp(name, "include")) | 122 | } else if (!strcmp(name, "include")) |
123 | parse_configfile(value, config_cb); | 123 | parse_configfile(value, config_cb); |
124 | } | 124 | } |
125 | 125 | ||
126 | static void querystring_cb(const char *name, const char *value) | 126 | static void querystring_cb(const char *name, const char *value) |
127 | { | 127 | { |
128 | if (!strcmp(name,"r")) { | 128 | if (!strcmp(name,"r")) { |
129 | ctx.qry.repo = xstrdup(value); | 129 | ctx.qry.repo = xstrdup(value); |
130 | ctx.repo = cgit_get_repoinfo(value); | 130 | ctx.repo = cgit_get_repoinfo(value); |
131 | } else if (!strcmp(name, "p")) { | 131 | } else if (!strcmp(name, "p")) { |
132 | ctx.qry.page = xstrdup(value); | 132 | ctx.qry.page = xstrdup(value); |
133 | } else if (!strcmp(name, "url")) { | 133 | } else if (!strcmp(name, "url")) { |
134 | ctx.qry.url = xstrdup(value); | 134 | ctx.qry.url = xstrdup(value); |
135 | cgit_parse_url(value); | 135 | cgit_parse_url(value); |
136 | } else if (!strcmp(name, "qt")) { | 136 | } else if (!strcmp(name, "qt")) { |
137 | ctx.qry.grep = xstrdup(value); | 137 | ctx.qry.grep = xstrdup(value); |
138 | } else if (!strcmp(name, "q")) { | 138 | } else if (!strcmp(name, "q")) { |
139 | ctx.qry.search = xstrdup(value); | 139 | ctx.qry.search = xstrdup(value); |
140 | } else if (!strcmp(name, "h")) { | 140 | } else if (!strcmp(name, "h")) { |
141 | ctx.qry.head = xstrdup(value); | 141 | ctx.qry.head = xstrdup(value); |
142 | ctx.qry.has_symref = 1; | 142 | ctx.qry.has_symref = 1; |
143 | } else if (!strcmp(name, "id")) { | 143 | } else if (!strcmp(name, "id")) { |
144 | ctx.qry.sha1 = xstrdup(value); | 144 | ctx.qry.sha1 = xstrdup(value); |
145 | ctx.qry.has_sha1 = 1; | 145 | ctx.qry.has_sha1 = 1; |
146 | } else if (!strcmp(name, "id2")) { | 146 | } else if (!strcmp(name, "id2")) { |
147 | ctx.qry.sha2 = xstrdup(value); | 147 | ctx.qry.sha2 = xstrdup(value); |
148 | ctx.qry.has_sha1 = 1; | 148 | ctx.qry.has_sha1 = 1; |
149 | } else if (!strcmp(name, "ofs")) { | 149 | } else if (!strcmp(name, "ofs")) { |
150 | ctx.qry.ofs = atoi(value); | 150 | ctx.qry.ofs = atoi(value); |
151 | } else if (!strcmp(name, "path")) { | 151 | } else if (!strcmp(name, "path")) { |
152 | ctx.qry.path = trim_end(value, '/'); | 152 | ctx.qry.path = trim_end(value, '/'); |
153 | } else if (!strcmp(name, "name")) { | 153 | } else if (!strcmp(name, "name")) { |
154 | ctx.qry.name = xstrdup(value); | 154 | ctx.qry.name = xstrdup(value); |
155 | } else if (!strcmp(name, "mimetype")) { | 155 | } else if (!strcmp(name, "mimetype")) { |
156 | ctx.qry.mimetype = xstrdup(value); | 156 | ctx.qry.mimetype = xstrdup(value); |
157 | } else if (!strcmp(name, "showmsg")) { | ||
158 | ctx.qry.showmsg = atoi(value); | ||
157 | } | 159 | } |
158 | } | 160 | } |
159 | 161 | ||
160 | static void prepare_context(struct cgit_context *ctx) | 162 | static void prepare_context(struct cgit_context *ctx) |
161 | { | 163 | { |
162 | memset(ctx, 0, sizeof(ctx)); | 164 | memset(ctx, 0, sizeof(ctx)); |
163 | ctx->cfg.agefile = "info/web/last-modified"; | 165 | ctx->cfg.agefile = "info/web/last-modified"; |
164 | ctx->cfg.nocache = 0; | 166 | ctx->cfg.nocache = 0; |
165 | ctx->cfg.cache_size = 0; | 167 | ctx->cfg.cache_size = 0; |
166 | ctx->cfg.cache_dynamic_ttl = 5; | 168 | ctx->cfg.cache_dynamic_ttl = 5; |
167 | ctx->cfg.cache_max_create_time = 5; | 169 | ctx->cfg.cache_max_create_time = 5; |
168 | ctx->cfg.cache_repo_ttl = 5; | 170 | ctx->cfg.cache_repo_ttl = 5; |
169 | ctx->cfg.cache_root = CGIT_CACHE_ROOT; | 171 | ctx->cfg.cache_root = CGIT_CACHE_ROOT; |
170 | ctx->cfg.cache_root_ttl = 5; | 172 | ctx->cfg.cache_root_ttl = 5; |
171 | ctx->cfg.cache_static_ttl = -1; | 173 | ctx->cfg.cache_static_ttl = -1; |
172 | ctx->cfg.css = "/cgit.css"; | 174 | ctx->cfg.css = "/cgit.css"; |
173 | ctx->cfg.logo = "/git-logo.png"; | 175 | ctx->cfg.logo = "/git-logo.png"; |
174 | ctx->cfg.local_time = 0; | 176 | ctx->cfg.local_time = 0; |
175 | ctx->cfg.max_repo_count = 50; | 177 | ctx->cfg.max_repo_count = 50; |
176 | ctx->cfg.max_commit_count = 50; | 178 | ctx->cfg.max_commit_count = 50; |
177 | ctx->cfg.max_lock_attempts = 5; | 179 | ctx->cfg.max_lock_attempts = 5; |
178 | ctx->cfg.max_msg_len = 80; | 180 | ctx->cfg.max_msg_len = 80; |
179 | ctx->cfg.max_repodesc_len = 80; | 181 | ctx->cfg.max_repodesc_len = 80; |
180 | ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; | 182 | ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; |
181 | ctx->cfg.renamelimit = -1; | 183 | ctx->cfg.renamelimit = -1; |
182 | ctx->cfg.robots = "index, nofollow"; | 184 | ctx->cfg.robots = "index, nofollow"; |
183 | ctx->cfg.root_title = "Git repository browser"; | 185 | ctx->cfg.root_title = "Git repository browser"; |
184 | ctx->cfg.root_desc = "a fast webinterface for the git dscm"; | 186 | ctx->cfg.root_desc = "a fast webinterface for the git dscm"; |
185 | ctx->cfg.script_name = CGIT_SCRIPT_NAME; | 187 | ctx->cfg.script_name = CGIT_SCRIPT_NAME; |
186 | ctx->cfg.summary_branches = 10; | 188 | ctx->cfg.summary_branches = 10; |
187 | ctx->cfg.summary_log = 10; | 189 | ctx->cfg.summary_log = 10; |
188 | ctx->cfg.summary_tags = 10; | 190 | ctx->cfg.summary_tags = 10; |
189 | ctx->page.mimetype = "text/html"; | 191 | ctx->page.mimetype = "text/html"; |
190 | ctx->page.charset = PAGE_ENCODING; | 192 | ctx->page.charset = PAGE_ENCODING; |
191 | ctx->page.filename = NULL; | 193 | ctx->page.filename = NULL; |
192 | ctx->page.size = 0; | 194 | ctx->page.size = 0; |
193 | ctx->page.modified = time(NULL); | 195 | ctx->page.modified = time(NULL); |
194 | ctx->page.expires = ctx->page.modified; | 196 | ctx->page.expires = ctx->page.modified; |
195 | } | 197 | } |
196 | 198 | ||
197 | struct refmatch { | 199 | struct refmatch { |
198 | char *req_ref; | 200 | char *req_ref; |
199 | char *first_ref; | 201 | char *first_ref; |
200 | int match; | 202 | int match; |
201 | }; | 203 | }; |
202 | 204 | ||
203 | int find_current_ref(const char *refname, const unsigned char *sha1, | 205 | int find_current_ref(const char *refname, const unsigned char *sha1, |
204 | int flags, void *cb_data) | 206 | int flags, void *cb_data) |
205 | { | 207 | { |
206 | struct refmatch *info; | 208 | struct refmatch *info; |
207 | 209 | ||
208 | info = (struct refmatch *)cb_data; | 210 | info = (struct refmatch *)cb_data; |
209 | if (!strcmp(refname, info->req_ref)) | 211 | if (!strcmp(refname, info->req_ref)) |
210 | info->match = 1; | 212 | info->match = 1; |
211 | if (!info->first_ref) | 213 | if (!info->first_ref) |
212 | info->first_ref = xstrdup(refname); | 214 | info->first_ref = xstrdup(refname); |
213 | return info->match; | 215 | return info->match; |
214 | } | 216 | } |
215 | 217 | ||
216 | char *find_default_branch(struct cgit_repo *repo) | 218 | char *find_default_branch(struct cgit_repo *repo) |
217 | { | 219 | { |
218 | struct refmatch info; | 220 | struct refmatch info; |
219 | char *ref; | 221 | char *ref; |
220 | 222 | ||
221 | info.req_ref = repo->defbranch; | 223 | info.req_ref = repo->defbranch; |
222 | info.first_ref = NULL; | 224 | info.first_ref = NULL; |
223 | info.match = 0; | 225 | info.match = 0; |
224 | for_each_branch_ref(find_current_ref, &info); | 226 | for_each_branch_ref(find_current_ref, &info); |
225 | if (info.match) | 227 | if (info.match) |
226 | ref = info.req_ref; | 228 | ref = info.req_ref; |
227 | else | 229 | else |
228 | ref = info.first_ref; | 230 | ref = info.first_ref; |
229 | if (ref) | 231 | if (ref) |
230 | ref = xstrdup(ref); | 232 | ref = xstrdup(ref); |
231 | return ref; | 233 | return ref; |
232 | } | 234 | } |
233 | 235 | ||
234 | static int prepare_repo_cmd(struct cgit_context *ctx) | 236 | static int prepare_repo_cmd(struct cgit_context *ctx) |
235 | { | 237 | { |
236 | char *tmp; | 238 | char *tmp; |
237 | unsigned char sha1[20]; | 239 | unsigned char sha1[20]; |
238 | int nongit = 0; | 240 | int nongit = 0; |
239 | 241 | ||
240 | setenv("GIT_DIR", ctx->repo->path, 1); | 242 | setenv("GIT_DIR", ctx->repo->path, 1); |
241 | setup_git_directory_gently(&nongit); | 243 | setup_git_directory_gently(&nongit); |
242 | if (nongit) { | 244 | if (nongit) { |
243 | ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, | 245 | ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, |
244 | "config error"); | 246 | "config error"); |
245 | tmp = fmt("Not a git repository: '%s'", ctx->repo->path); | 247 | tmp = fmt("Not a git repository: '%s'", ctx->repo->path); |
246 | ctx->repo = NULL; | 248 | ctx->repo = NULL; |
247 | cgit_print_http_headers(ctx); | 249 | cgit_print_http_headers(ctx); |
248 | cgit_print_docstart(ctx); | 250 | cgit_print_docstart(ctx); |
249 | cgit_print_pageheader(ctx); | 251 | cgit_print_pageheader(ctx); |
250 | cgit_print_error(tmp); | 252 | cgit_print_error(tmp); |
251 | cgit_print_docend(); | 253 | cgit_print_docend(); |
252 | return 1; | 254 | return 1; |
@@ -28,192 +28,193 @@ | |||
28 | 28 | ||
29 | 29 | ||
30 | /* | 30 | /* |
31 | * Limits used for relative dates | 31 | * Limits used for relative dates |
32 | */ | 32 | */ |
33 | #define TM_MIN 60 | 33 | #define TM_MIN 60 |
34 | #define TM_HOUR (TM_MIN * 60) | 34 | #define TM_HOUR (TM_MIN * 60) |
35 | #define TM_DAY (TM_HOUR * 24) | 35 | #define TM_DAY (TM_HOUR * 24) |
36 | #define TM_WEEK (TM_DAY * 7) | 36 | #define TM_WEEK (TM_DAY * 7) |
37 | #define TM_YEAR (TM_DAY * 365) | 37 | #define TM_YEAR (TM_DAY * 365) |
38 | #define TM_MONTH (TM_YEAR / 12.0) | 38 | #define TM_MONTH (TM_YEAR / 12.0) |
39 | 39 | ||
40 | 40 | ||
41 | /* | 41 | /* |
42 | * Default encoding | 42 | * Default encoding |
43 | */ | 43 | */ |
44 | #define PAGE_ENCODING "UTF-8" | 44 | #define PAGE_ENCODING "UTF-8" |
45 | 45 | ||
46 | typedef void (*configfn)(const char *name, const char *value); | 46 | typedef void (*configfn)(const char *name, const char *value); |
47 | typedef void (*filepair_fn)(struct diff_filepair *pair); | 47 | typedef void (*filepair_fn)(struct diff_filepair *pair); |
48 | typedef void (*linediff_fn)(char *line, int len); | 48 | typedef void (*linediff_fn)(char *line, int len); |
49 | 49 | ||
50 | struct cgit_repo { | 50 | struct cgit_repo { |
51 | char *url; | 51 | char *url; |
52 | char *name; | 52 | char *name; |
53 | char *path; | 53 | char *path; |
54 | char *desc; | 54 | char *desc; |
55 | char *owner; | 55 | char *owner; |
56 | char *defbranch; | 56 | char *defbranch; |
57 | char *group; | 57 | char *group; |
58 | char *module_link; | 58 | char *module_link; |
59 | char *readme; | 59 | char *readme; |
60 | char *clone_url; | 60 | char *clone_url; |
61 | int snapshots; | 61 | int snapshots; |
62 | int enable_log_filecount; | 62 | int enable_log_filecount; |
63 | int enable_log_linecount; | 63 | int enable_log_linecount; |
64 | }; | 64 | }; |
65 | 65 | ||
66 | struct cgit_repolist { | 66 | struct cgit_repolist { |
67 | int length; | 67 | int length; |
68 | int count; | 68 | int count; |
69 | struct cgit_repo *repos; | 69 | struct cgit_repo *repos; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | struct commitinfo { | 72 | struct commitinfo { |
73 | struct commit *commit; | 73 | struct commit *commit; |
74 | char *author; | 74 | char *author; |
75 | char *author_email; | 75 | char *author_email; |
76 | unsigned long author_date; | 76 | unsigned long author_date; |
77 | char *committer; | 77 | char *committer; |
78 | char *committer_email; | 78 | char *committer_email; |
79 | unsigned long committer_date; | 79 | unsigned long committer_date; |
80 | char *subject; | 80 | char *subject; |
81 | char *msg; | 81 | char *msg; |
82 | char *msg_encoding; | 82 | char *msg_encoding; |
83 | }; | 83 | }; |
84 | 84 | ||
85 | struct taginfo { | 85 | struct taginfo { |
86 | char *tagger; | 86 | char *tagger; |
87 | char *tagger_email; | 87 | char *tagger_email; |
88 | unsigned long tagger_date; | 88 | unsigned long tagger_date; |
89 | char *msg; | 89 | char *msg; |
90 | }; | 90 | }; |
91 | 91 | ||
92 | struct refinfo { | 92 | struct refinfo { |
93 | const char *refname; | 93 | const char *refname; |
94 | struct object *object; | 94 | struct object *object; |
95 | union { | 95 | union { |
96 | struct taginfo *tag; | 96 | struct taginfo *tag; |
97 | struct commitinfo *commit; | 97 | struct commitinfo *commit; |
98 | }; | 98 | }; |
99 | }; | 99 | }; |
100 | 100 | ||
101 | struct reflist { | 101 | struct reflist { |
102 | struct refinfo **refs; | 102 | struct refinfo **refs; |
103 | int alloc; | 103 | int alloc; |
104 | int count; | 104 | int count; |
105 | }; | 105 | }; |
106 | 106 | ||
107 | struct cgit_query { | 107 | struct cgit_query { |
108 | int has_symref; | 108 | int has_symref; |
109 | int has_sha1; | 109 | int has_sha1; |
110 | char *raw; | 110 | char *raw; |
111 | char *repo; | 111 | char *repo; |
112 | char *page; | 112 | char *page; |
113 | char *search; | 113 | char *search; |
114 | char *grep; | 114 | char *grep; |
115 | char *head; | 115 | char *head; |
116 | char *sha1; | 116 | char *sha1; |
117 | char *sha2; | 117 | char *sha2; |
118 | char *path; | 118 | char *path; |
119 | char *name; | 119 | char *name; |
120 | char *mimetype; | 120 | char *mimetype; |
121 | char *url; | 121 | char *url; |
122 | int ofs; | 122 | int ofs; |
123 | int nohead; | 123 | int nohead; |
124 | int showmsg; | ||
124 | }; | 125 | }; |
125 | 126 | ||
126 | struct cgit_config { | 127 | struct cgit_config { |
127 | char *agefile; | 128 | char *agefile; |
128 | char *cache_root; | 129 | char *cache_root; |
129 | char *clone_prefix; | 130 | char *clone_prefix; |
130 | char *css; | 131 | char *css; |
131 | char *favicon; | 132 | char *favicon; |
132 | char *footer; | 133 | char *footer; |
133 | char *index_header; | 134 | char *index_header; |
134 | char *index_info; | 135 | char *index_info; |
135 | char *logo; | 136 | char *logo; |
136 | char *logo_link; | 137 | char *logo_link; |
137 | char *module_link; | 138 | char *module_link; |
138 | char *repo_group; | 139 | char *repo_group; |
139 | char *robots; | 140 | char *robots; |
140 | char *root_title; | 141 | char *root_title; |
141 | char *root_desc; | 142 | char *root_desc; |
142 | char *root_readme; | 143 | char *root_readme; |
143 | char *script_name; | 144 | char *script_name; |
144 | char *virtual_root; | 145 | char *virtual_root; |
145 | int cache_size; | 146 | int cache_size; |
146 | int cache_dynamic_ttl; | 147 | int cache_dynamic_ttl; |
147 | int cache_max_create_time; | 148 | int cache_max_create_time; |
148 | int cache_repo_ttl; | 149 | int cache_repo_ttl; |
149 | int cache_root_ttl; | 150 | int cache_root_ttl; |
150 | int cache_static_ttl; | 151 | int cache_static_ttl; |
151 | int enable_index_links; | 152 | int enable_index_links; |
152 | int enable_log_filecount; | 153 | int enable_log_filecount; |
153 | int enable_log_linecount; | 154 | int enable_log_linecount; |
154 | int local_time; | 155 | int local_time; |
155 | int max_repo_count; | 156 | int max_repo_count; |
156 | int max_commit_count; | 157 | int max_commit_count; |
157 | int max_lock_attempts; | 158 | int max_lock_attempts; |
158 | int max_msg_len; | 159 | int max_msg_len; |
159 | int max_repodesc_len; | 160 | int max_repodesc_len; |
160 | int nocache; | 161 | int nocache; |
161 | int renamelimit; | 162 | int renamelimit; |
162 | int snapshots; | 163 | int snapshots; |
163 | int summary_branches; | 164 | int summary_branches; |
164 | int summary_log; | 165 | int summary_log; |
165 | int summary_tags; | 166 | int summary_tags; |
166 | }; | 167 | }; |
167 | 168 | ||
168 | struct cgit_page { | 169 | struct cgit_page { |
169 | time_t modified; | 170 | time_t modified; |
170 | time_t expires; | 171 | time_t expires; |
171 | size_t size; | 172 | size_t size; |
172 | char *mimetype; | 173 | char *mimetype; |
173 | char *charset; | 174 | char *charset; |
174 | char *filename; | 175 | char *filename; |
175 | char *title; | 176 | char *title; |
176 | }; | 177 | }; |
177 | 178 | ||
178 | struct cgit_context { | 179 | struct cgit_context { |
179 | struct cgit_query qry; | 180 | struct cgit_query qry; |
180 | struct cgit_config cfg; | 181 | struct cgit_config cfg; |
181 | struct cgit_repo *repo; | 182 | struct cgit_repo *repo; |
182 | struct cgit_page page; | 183 | struct cgit_page page; |
183 | }; | 184 | }; |
184 | 185 | ||
185 | struct cgit_snapshot_format { | 186 | struct cgit_snapshot_format { |
186 | const char *suffix; | 187 | const char *suffix; |
187 | const char *mimetype; | 188 | const char *mimetype; |
188 | write_archive_fn_t write_func; | 189 | write_archive_fn_t write_func; |
189 | int bit; | 190 | int bit; |
190 | }; | 191 | }; |
191 | 192 | ||
192 | extern const char *cgit_version; | 193 | extern const char *cgit_version; |
193 | 194 | ||
194 | extern struct cgit_repolist cgit_repolist; | 195 | extern struct cgit_repolist cgit_repolist; |
195 | extern struct cgit_context ctx; | 196 | extern struct cgit_context ctx; |
196 | extern const struct cgit_snapshot_format cgit_snapshot_formats[]; | 197 | extern const struct cgit_snapshot_format cgit_snapshot_formats[]; |
197 | 198 | ||
198 | extern struct cgit_repo *cgit_add_repo(const char *url); | 199 | extern struct cgit_repo *cgit_add_repo(const char *url); |
199 | extern struct cgit_repo *cgit_get_repoinfo(const char *url); | 200 | extern struct cgit_repo *cgit_get_repoinfo(const char *url); |
200 | extern void cgit_repo_config_cb(const char *name, const char *value); | 201 | extern void cgit_repo_config_cb(const char *name, const char *value); |
201 | 202 | ||
202 | extern int chk_zero(int result, char *msg); | 203 | extern int chk_zero(int result, char *msg); |
203 | extern int chk_positive(int result, char *msg); | 204 | extern int chk_positive(int result, char *msg); |
204 | extern int chk_non_negative(int result, char *msg); | 205 | extern int chk_non_negative(int result, char *msg); |
205 | 206 | ||
206 | extern char *trim_end(const char *str, char c); | 207 | extern char *trim_end(const char *str, char c); |
207 | extern char *strlpart(char *txt, int maxlen); | 208 | extern char *strlpart(char *txt, int maxlen); |
208 | extern char *strrpart(char *txt, int maxlen); | 209 | extern char *strrpart(char *txt, int maxlen); |
209 | 210 | ||
210 | extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); | 211 | extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); |
211 | extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, | 212 | extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, |
212 | int flags, void *cb_data); | 213 | int flags, void *cb_data); |
213 | 214 | ||
214 | extern void *cgit_free_commitinfo(struct commitinfo *info); | 215 | extern void *cgit_free_commitinfo(struct commitinfo *info); |
215 | 216 | ||
216 | extern int cgit_diff_files(const unsigned char *old_sha1, | 217 | extern int cgit_diff_files(const unsigned char *old_sha1, |
217 | const unsigned char *new_sha1, | 218 | const unsigned char *new_sha1, |
218 | linediff_fn fn); | 219 | linediff_fn fn); |
219 | 220 | ||
@@ -1,155 +1,177 @@ | |||
1 | /* ui-log.c: functions for log output | 1 | /* ui-log.c: functions for log 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 "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 | 12 | ||
13 | int files, add_lines, rem_lines; | 13 | int files, add_lines, rem_lines; |
14 | 14 | ||
15 | void count_lines(char *line, int size) | 15 | void count_lines(char *line, int size) |
16 | { | 16 | { |
17 | if (size <= 0) | 17 | if (size <= 0) |
18 | return; | 18 | return; |
19 | 19 | ||
20 | if (line[0] == '+') | 20 | if (line[0] == '+') |
21 | add_lines++; | 21 | add_lines++; |
22 | 22 | ||
23 | else if (line[0] == '-') | 23 | else if (line[0] == '-') |
24 | rem_lines++; | 24 | rem_lines++; |
25 | } | 25 | } |
26 | 26 | ||
27 | void inspect_files(struct diff_filepair *pair) | 27 | void inspect_files(struct diff_filepair *pair) |
28 | { | 28 | { |
29 | files++; | 29 | files++; |
30 | if (ctx.repo->enable_log_linecount) | 30 | if (ctx.repo->enable_log_linecount) |
31 | cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines); | 31 | cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines); |
32 | } | 32 | } |
33 | 33 | ||
34 | void print_commit(struct commit *commit) | 34 | void print_commit(struct commit *commit) |
35 | { | 35 | { |
36 | struct commitinfo *info; | 36 | struct commitinfo *info; |
37 | char *tmp; | 37 | char *tmp; |
38 | 38 | ||
39 | info = cgit_parse_commit(commit); | 39 | info = cgit_parse_commit(commit); |
40 | html("<tr><td>"); | 40 | html("<tr><td>"); |
41 | tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1)); | 41 | tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1)); |
42 | tmp = cgit_pageurl(ctx.repo->url, "commit", tmp); | 42 | tmp = cgit_pageurl(ctx.repo->url, "commit", tmp); |
43 | html_link_open(tmp, NULL, NULL); | 43 | html_link_open(tmp, NULL, NULL); |
44 | cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); | 44 | cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); |
45 | html_link_close(); | 45 | html_link_close(); |
46 | html("</td><td>"); | 46 | html("</td><td>"); |
47 | if (ctx.qry.showmsg) | ||
48 | html("<u>"); | ||
47 | cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, | 49 | cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, |
48 | sha1_to_hex(commit->object.sha1)); | 50 | sha1_to_hex(commit->object.sha1)); |
51 | if (ctx.qry.showmsg) | ||
52 | html("</u>"); | ||
49 | html("</td><td>"); | 53 | html("</td><td>"); |
50 | html_txt(info->author); | 54 | html_txt(info->author); |
51 | if (ctx.repo->enable_log_filecount) { | 55 | if (ctx.repo->enable_log_filecount) { |
52 | files = 0; | 56 | files = 0; |
53 | add_lines = 0; | 57 | add_lines = 0; |
54 | rem_lines = 0; | 58 | rem_lines = 0; |
55 | cgit_diff_commit(commit, inspect_files); | 59 | cgit_diff_commit(commit, inspect_files); |
56 | html("</td><td>"); | 60 | html("</td><td>"); |
57 | htmlf("%d", files); | 61 | htmlf("%d", files); |
58 | if (ctx.repo->enable_log_linecount) { | 62 | if (ctx.repo->enable_log_linecount) { |
59 | html("</td><td>"); | 63 | html("</td><td>"); |
60 | htmlf("-%d/+%d", rem_lines, add_lines); | 64 | htmlf("-%d/+%d", rem_lines, add_lines); |
61 | } | 65 | } |
62 | } | 66 | } |
63 | html("</td></tr>\n"); | 67 | html("</td></tr>\n"); |
68 | if (ctx.qry.showmsg) { | ||
69 | html("<tr class='nohover'><td></td><td><div class='commit-msg'>"); | ||
70 | html_txt(info->msg); | ||
71 | html("</div><br/></td><td></td>"); | ||
72 | if (ctx.repo->enable_log_filecount) { | ||
73 | html("<td></td>"); | ||
74 | if (ctx.repo->enable_log_linecount) | ||
75 | html("<td></td>"); | ||
76 | } | ||
77 | html("</tr>\n"); | ||
78 | } | ||
64 | cgit_free_commitinfo(info); | 79 | cgit_free_commitinfo(info); |
65 | } | 80 | } |
66 | 81 | ||
67 | 82 | ||
68 | void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern, | 83 | void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern, |
69 | char *path, int pager) | 84 | char *path, int pager) |
70 | { | 85 | { |
71 | struct rev_info rev; | 86 | struct rev_info rev; |
72 | struct commit *commit; | 87 | struct commit *commit; |
73 | const char *argv[] = {NULL, tip, NULL, NULL, NULL}; | 88 | const char *argv[] = {NULL, tip, NULL, NULL, NULL}; |
74 | int argc = 2; | 89 | int argc = 2; |
75 | int i, columns = 3; | 90 | int i, columns = 3; |
76 | 91 | ||
77 | if (!tip) | 92 | if (!tip) |
78 | argv[1] = ctx.qry.head; | 93 | argv[1] = ctx.qry.head; |
79 | 94 | ||
80 | if (grep && pattern && (!strcmp(grep, "grep") || | 95 | if (grep && pattern && (!strcmp(grep, "grep") || |
81 | !strcmp(grep, "author") || | 96 | !strcmp(grep, "author") || |
82 | !strcmp(grep, "committer"))) | 97 | !strcmp(grep, "committer"))) |
83 | argv[argc++] = fmt("--%s=%s", grep, pattern); | 98 | argv[argc++] = fmt("--%s=%s", grep, pattern); |
84 | 99 | ||
85 | if (path) { | 100 | if (path) { |
86 | argv[argc++] = "--"; | 101 | argv[argc++] = "--"; |
87 | argv[argc++] = path; | 102 | argv[argc++] = path; |
88 | } | 103 | } |
89 | init_revisions(&rev, NULL); | 104 | init_revisions(&rev, NULL); |
90 | rev.abbrev = DEFAULT_ABBREV; | 105 | rev.abbrev = DEFAULT_ABBREV; |
91 | rev.commit_format = CMIT_FMT_DEFAULT; | 106 | rev.commit_format = CMIT_FMT_DEFAULT; |
92 | rev.verbose_header = 1; | 107 | rev.verbose_header = 1; |
93 | rev.show_root_diff = 0; | 108 | rev.show_root_diff = 0; |
94 | setup_revisions(argc, argv, &rev, NULL); | 109 | setup_revisions(argc, argv, &rev, NULL); |
95 | rev.grep_filter.regflags |= REG_ICASE; | 110 | rev.grep_filter.regflags |= REG_ICASE; |
96 | compile_grep_patterns(&rev.grep_filter); | 111 | compile_grep_patterns(&rev.grep_filter); |
97 | prepare_revision_walk(&rev); | 112 | prepare_revision_walk(&rev); |
98 | 113 | ||
99 | if (pager) | 114 | if (pager) |
100 | html("<table class='list nowrap'>"); | 115 | html("<table class='list nowrap'>"); |
101 | 116 | ||
102 | html("<tr class='nohover'><th class='left'>Age</th>" | 117 | html("<tr class='nohover'><th class='left'>Age</th>" |
103 | "<th class='left'>Commit message</th>" | 118 | "<th class='left'>Commit message"); |
104 | "<th class='left'>Author</th>"); | 119 | if (pager) { |
120 | html(" ("); | ||
121 | cgit_log_link("toggle", NULL, NULL, ctx.qry.head, ctx.qry.sha1, | ||
122 | ctx.qry.path, ctx.qry.ofs, ctx.qry.grep, | ||
123 | ctx.qry.search, ctx.qry.showmsg ? 0 : 1); | ||
124 | html(")"); | ||
125 | } | ||
126 | html("</th><th class='left'>Author</th>"); | ||
105 | if (ctx.repo->enable_log_filecount) { | 127 | if (ctx.repo->enable_log_filecount) { |
106 | html("<th class='left'>Files</th>"); | 128 | html("<th class='left'>Files</th>"); |
107 | columns++; | 129 | columns++; |
108 | if (ctx.repo->enable_log_linecount) { | 130 | if (ctx.repo->enable_log_linecount) { |
109 | html("<th class='left'>Lines</th>"); | 131 | html("<th class='left'>Lines</th>"); |
110 | columns++; | 132 | columns++; |
111 | } | 133 | } |
112 | } | 134 | } |
113 | html("</tr>\n"); | 135 | html("</tr>\n"); |
114 | 136 | ||
115 | if (ofs<0) | 137 | if (ofs<0) |
116 | ofs = 0; | 138 | ofs = 0; |
117 | 139 | ||
118 | for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) { | 140 | for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) { |
119 | free(commit->buffer); | 141 | free(commit->buffer); |
120 | commit->buffer = NULL; | 142 | commit->buffer = NULL; |
121 | free_commit_list(commit->parents); | 143 | free_commit_list(commit->parents); |
122 | commit->parents = NULL; | 144 | commit->parents = NULL; |
123 | } | 145 | } |
124 | 146 | ||
125 | for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) { | 147 | for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) { |
126 | print_commit(commit); | 148 | print_commit(commit); |
127 | free(commit->buffer); | 149 | free(commit->buffer); |
128 | commit->buffer = NULL; | 150 | commit->buffer = NULL; |
129 | free_commit_list(commit->parents); | 151 | free_commit_list(commit->parents); |
130 | commit->parents = NULL; | 152 | commit->parents = NULL; |
131 | } | 153 | } |
132 | if (pager) { | 154 | if (pager) { |
133 | htmlf("</table><div class='pager'>", | 155 | htmlf("</table><div class='pager'>", |
134 | columns); | 156 | columns); |
135 | if (ofs > 0) { | 157 | if (ofs > 0) { |
136 | cgit_log_link("[prev]", NULL, NULL, ctx.qry.head, | 158 | cgit_log_link("[prev]", NULL, NULL, ctx.qry.head, |
137 | ctx.qry.sha1, ctx.qry.path, | 159 | ctx.qry.sha1, ctx.qry.path, |
138 | ofs - cnt, ctx.qry.grep, | 160 | ofs - cnt, ctx.qry.grep, |
139 | ctx.qry.search); | 161 | ctx.qry.search, ctx.qry.showmsg); |
140 | html(" "); | 162 | html(" "); |
141 | } | 163 | } |
142 | if ((commit = get_revision(&rev)) != NULL) { | 164 | if ((commit = get_revision(&rev)) != NULL) { |
143 | cgit_log_link("[next]", NULL, NULL, ctx.qry.head, | 165 | cgit_log_link("[next]", NULL, NULL, ctx.qry.head, |
144 | ctx.qry.sha1, ctx.qry.path, | 166 | ctx.qry.sha1, ctx.qry.path, |
145 | ofs + cnt, ctx.qry.grep, | 167 | ofs + cnt, ctx.qry.grep, |
146 | ctx.qry.search); | 168 | ctx.qry.search, ctx.qry.showmsg); |
147 | } | 169 | } |
148 | html("</div>"); | 170 | html("</div>"); |
149 | } else if ((commit = get_revision(&rev)) != NULL) { | 171 | } else if ((commit = get_revision(&rev)) != NULL) { |
150 | html("<tr class='nohover'><td colspan='3'>"); | 172 | html("<tr class='nohover'><td colspan='3'>"); |
151 | cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL, NULL, 0, | 173 | cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL, NULL, 0, |
152 | NULL, NULL); | 174 | NULL, NULL, ctx.qry.showmsg); |
153 | html("</td></tr>\n"); | 175 | html("</td></tr>\n"); |
154 | } | 176 | } |
155 | } | 177 | } |
@@ -1,157 +1,158 @@ | |||
1 | /* ui-refs.c: browse symbolic refs | 1 | /* ui-refs.c: browse symbolic refs |
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 | 12 | ||
13 | static int header; | 13 | static int header; |
14 | 14 | ||
15 | static int cmp_age(int age1, int age2) | 15 | static int cmp_age(int age1, int age2) |
16 | { | 16 | { |
17 | if (age1 != 0 && age2 != 0) | 17 | if (age1 != 0 && age2 != 0) |
18 | return age2 - age1; | 18 | return age2 - age1; |
19 | 19 | ||
20 | if (age1 == 0 && age2 == 0) | 20 | if (age1 == 0 && age2 == 0) |
21 | return 0; | 21 | return 0; |
22 | 22 | ||
23 | if (age1 == 0) | 23 | if (age1 == 0) |
24 | return +1; | 24 | return +1; |
25 | 25 | ||
26 | return -1; | 26 | return -1; |
27 | } | 27 | } |
28 | 28 | ||
29 | static int cmp_ref_name(const void *a, const void *b) | 29 | static int cmp_ref_name(const void *a, const void *b) |
30 | { | 30 | { |
31 | struct refinfo *r1 = *(struct refinfo **)a; | 31 | struct refinfo *r1 = *(struct refinfo **)a; |
32 | struct refinfo *r2 = *(struct refinfo **)b; | 32 | struct refinfo *r2 = *(struct refinfo **)b; |
33 | 33 | ||
34 | return strcmp(r1->refname, r2->refname); | 34 | return strcmp(r1->refname, r2->refname); |
35 | } | 35 | } |
36 | 36 | ||
37 | static int cmp_branch_age(const void *a, const void *b) | 37 | static int cmp_branch_age(const void *a, const void *b) |
38 | { | 38 | { |
39 | struct refinfo *r1 = *(struct refinfo **)a; | 39 | struct refinfo *r1 = *(struct refinfo **)a; |
40 | struct refinfo *r2 = *(struct refinfo **)b; | 40 | struct refinfo *r2 = *(struct refinfo **)b; |
41 | 41 | ||
42 | return cmp_age(r1->commit->committer_date, r2->commit->committer_date); | 42 | return cmp_age(r1->commit->committer_date, r2->commit->committer_date); |
43 | } | 43 | } |
44 | 44 | ||
45 | static int cmp_tag_age(const void *a, const void *b) | 45 | static int cmp_tag_age(const void *a, const void *b) |
46 | { | 46 | { |
47 | struct refinfo *r1 = *(struct refinfo **)a; | 47 | struct refinfo *r1 = *(struct refinfo **)a; |
48 | struct refinfo *r2 = *(struct refinfo **)b; | 48 | struct refinfo *r2 = *(struct refinfo **)b; |
49 | 49 | ||
50 | return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date); | 50 | return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date); |
51 | } | 51 | } |
52 | 52 | ||
53 | static int print_branch(struct refinfo *ref) | 53 | static int print_branch(struct refinfo *ref) |
54 | { | 54 | { |
55 | struct commitinfo *info = ref->commit; | 55 | struct commitinfo *info = ref->commit; |
56 | char *name = (char *)ref->refname; | 56 | char *name = (char *)ref->refname; |
57 | 57 | ||
58 | if (!info) | 58 | if (!info) |
59 | return 1; | 59 | return 1; |
60 | html("<tr><td>"); | 60 | html("<tr><td>"); |
61 | cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL); | 61 | cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL, |
62 | ctx.qry.showmsg); | ||
62 | html("</td><td>"); | 63 | html("</td><td>"); |
63 | 64 | ||
64 | if (ref->object->type == OBJ_COMMIT) { | 65 | if (ref->object->type == OBJ_COMMIT) { |
65 | cgit_commit_link(info->subject, NULL, NULL, name, NULL); | 66 | cgit_commit_link(info->subject, NULL, NULL, name, NULL); |
66 | html("</td><td>"); | 67 | html("</td><td>"); |
67 | html_txt(info->author); | 68 | html_txt(info->author); |
68 | html("</td><td colspan='2'>"); | 69 | html("</td><td colspan='2'>"); |
69 | cgit_print_age(info->commit->date, -1, NULL); | 70 | cgit_print_age(info->commit->date, -1, NULL); |
70 | } else { | 71 | } else { |
71 | html("</td><td></td><td>"); | 72 | html("</td><td></td><td>"); |
72 | cgit_object_link(ref->object); | 73 | cgit_object_link(ref->object); |
73 | } | 74 | } |
74 | html("</td></tr>\n"); | 75 | html("</td></tr>\n"); |
75 | return 0; | 76 | return 0; |
76 | } | 77 | } |
77 | 78 | ||
78 | static void print_tag_header() | 79 | static void print_tag_header() |
79 | { | 80 | { |
80 | html("<tr class='nohover'><th class='left'>Tag</th>" | 81 | html("<tr class='nohover'><th class='left'>Tag</th>" |
81 | "<th class='left'>Reference</th>" | 82 | "<th class='left'>Reference</th>" |
82 | "<th class='left'>Author</th>" | 83 | "<th class='left'>Author</th>" |
83 | "<th class='left' colspan='2'>Age</th></tr>\n"); | 84 | "<th class='left' colspan='2'>Age</th></tr>\n"); |
84 | header = 1; | 85 | header = 1; |
85 | } | 86 | } |
86 | 87 | ||
87 | static int print_tag(struct refinfo *ref) | 88 | static int print_tag(struct refinfo *ref) |
88 | { | 89 | { |
89 | struct tag *tag; | 90 | struct tag *tag; |
90 | struct taginfo *info; | 91 | struct taginfo *info; |
91 | char *name = (char *)ref->refname; | 92 | char *name = (char *)ref->refname; |
92 | 93 | ||
93 | if (ref->object->type == OBJ_TAG) { | 94 | if (ref->object->type == OBJ_TAG) { |
94 | tag = (struct tag *)ref->object; | 95 | tag = (struct tag *)ref->object; |
95 | info = ref->tag; | 96 | info = ref->tag; |
96 | if (!tag || !info) | 97 | if (!tag || !info) |
97 | return 1; | 98 | return 1; |
98 | html("<tr><td>"); | 99 | html("<tr><td>"); |
99 | cgit_tag_link(name, NULL, NULL, ctx.qry.head, name); | 100 | cgit_tag_link(name, NULL, NULL, ctx.qry.head, name); |
100 | html("</td><td>"); | 101 | html("</td><td>"); |
101 | cgit_object_link(tag->tagged); | 102 | cgit_object_link(tag->tagged); |
102 | html("</td><td>"); | 103 | html("</td><td>"); |
103 | if (info->tagger) | 104 | if (info->tagger) |
104 | html(info->tagger); | 105 | html(info->tagger); |
105 | html("</td><td colspan='2'>"); | 106 | html("</td><td colspan='2'>"); |
106 | if (info->tagger_date > 0) | 107 | if (info->tagger_date > 0) |
107 | cgit_print_age(info->tagger_date, -1, NULL); | 108 | cgit_print_age(info->tagger_date, -1, NULL); |
108 | html("</td></tr>\n"); | 109 | html("</td></tr>\n"); |
109 | } else { | 110 | } else { |
110 | if (!header) | 111 | if (!header) |
111 | print_tag_header(); | 112 | print_tag_header(); |
112 | html("<tr><td>"); | 113 | html("<tr><td>"); |
113 | html_txt(name); | 114 | html_txt(name); |
114 | html("</td><td>"); | 115 | html("</td><td>"); |
115 | cgit_object_link(ref->object); | 116 | cgit_object_link(ref->object); |
116 | html("</td></tr>\n"); | 117 | html("</td></tr>\n"); |
117 | } | 118 | } |
118 | return 0; | 119 | return 0; |
119 | } | 120 | } |
120 | 121 | ||
121 | static void print_refs_link(char *path) | 122 | static void print_refs_link(char *path) |
122 | { | 123 | { |
123 | html("<tr class='nohover'><td colspan='4'>"); | 124 | html("<tr class='nohover'><td colspan='4'>"); |
124 | cgit_refs_link("[...]", NULL, NULL, ctx.qry.head, NULL, path); | 125 | cgit_refs_link("[...]", NULL, NULL, ctx.qry.head, NULL, path); |
125 | html("</td></tr>"); | 126 | html("</td></tr>"); |
126 | } | 127 | } |
127 | 128 | ||
128 | void cgit_print_branches(int maxcount) | 129 | void cgit_print_branches(int maxcount) |
129 | { | 130 | { |
130 | struct reflist list; | 131 | struct reflist list; |
131 | int i; | 132 | int i; |
132 | 133 | ||
133 | html("<tr class='nohover'><th class='left'>Branch</th>" | 134 | html("<tr class='nohover'><th class='left'>Branch</th>" |
134 | "<th class='left'>Commit message</th>" | 135 | "<th class='left'>Commit message</th>" |
135 | "<th class='left'>Author</th>" | 136 | "<th class='left'>Author</th>" |
136 | "<th class='left' colspan='2'>Age</th></tr>\n"); | 137 | "<th class='left' colspan='2'>Age</th></tr>\n"); |
137 | 138 | ||
138 | list.refs = NULL; | 139 | list.refs = NULL; |
139 | list.alloc = list.count = 0; | 140 | list.alloc = list.count = 0; |
140 | for_each_branch_ref(cgit_refs_cb, &list); | 141 | for_each_branch_ref(cgit_refs_cb, &list); |
141 | 142 | ||
142 | if (maxcount == 0 || maxcount > list.count) | 143 | if (maxcount == 0 || maxcount > list.count) |
143 | maxcount = list.count; | 144 | maxcount = list.count; |
144 | 145 | ||
145 | if (maxcount < list.count) { | 146 | if (maxcount < list.count) { |
146 | qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age); | 147 | qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age); |
147 | qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name); | 148 | qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name); |
148 | } | 149 | } |
149 | 150 | ||
150 | for(i=0; i<maxcount; i++) | 151 | for(i=0; i<maxcount; i++) |
151 | print_branch(list.refs[i]); | 152 | print_branch(list.refs[i]); |
152 | 153 | ||
153 | if (maxcount < list.count) | 154 | if (maxcount < list.count) |
154 | print_refs_link("heads"); | 155 | print_refs_link("heads"); |
155 | } | 156 | } |
156 | 157 | ||
157 | void cgit_print_tags(int maxcount) | 158 | void cgit_print_tags(int maxcount) |
diff --git a/ui-repolist.c b/ui-repolist.c index c23232c..5833140 100644 --- a/ui-repolist.c +++ b/ui-repolist.c | |||
@@ -53,115 +53,115 @@ int is_match(struct cgit_repo *repo) | |||
53 | return 1; | 53 | return 1; |
54 | if (repo->name && strcasestr(repo->name, ctx.qry.search)) | 54 | if (repo->name && strcasestr(repo->name, ctx.qry.search)) |
55 | return 1; | 55 | return 1; |
56 | if (repo->desc && strcasestr(repo->desc, ctx.qry.search)) | 56 | if (repo->desc && strcasestr(repo->desc, ctx.qry.search)) |
57 | return 1; | 57 | return 1; |
58 | if (repo->owner && strcasestr(repo->owner, ctx.qry.search)) | 58 | if (repo->owner && strcasestr(repo->owner, ctx.qry.search)) |
59 | return 1; | 59 | return 1; |
60 | return 0; | 60 | return 0; |
61 | } | 61 | } |
62 | 62 | ||
63 | int is_in_url(struct cgit_repo *repo) | 63 | int is_in_url(struct cgit_repo *repo) |
64 | { | 64 | { |
65 | if (!ctx.qry.url) | 65 | if (!ctx.qry.url) |
66 | return 1; | 66 | return 1; |
67 | if (repo->url && !prefixcmp(repo->url, ctx.qry.url)) | 67 | if (repo->url && !prefixcmp(repo->url, ctx.qry.url)) |
68 | return 1; | 68 | return 1; |
69 | return 0; | 69 | return 0; |
70 | } | 70 | } |
71 | 71 | ||
72 | void print_header(int columns) | 72 | void print_header(int columns) |
73 | { | 73 | { |
74 | html("<tr class='nohover'>" | 74 | html("<tr class='nohover'>" |
75 | "<th class='left'>Name</th>" | 75 | "<th class='left'>Name</th>" |
76 | "<th class='left'>Description</th>" | 76 | "<th class='left'>Description</th>" |
77 | "<th class='left'>Owner</th>" | 77 | "<th class='left'>Owner</th>" |
78 | "<th class='left'>Idle</th>"); | 78 | "<th class='left'>Idle</th>"); |
79 | if (ctx.cfg.enable_index_links) | 79 | if (ctx.cfg.enable_index_links) |
80 | html("<th class='left'>Links</th>"); | 80 | html("<th class='left'>Links</th>"); |
81 | html("</tr>\n"); | 81 | html("</tr>\n"); |
82 | } | 82 | } |
83 | 83 | ||
84 | 84 | ||
85 | void print_pager(int items, int pagelen, char *search) | 85 | void print_pager(int items, int pagelen, char *search) |
86 | { | 86 | { |
87 | int i; | 87 | int i; |
88 | html("<div class='pager'>"); | 88 | html("<div class='pager'>"); |
89 | for(i = 0; i * pagelen < items; i++) | 89 | for(i = 0; i * pagelen < items; i++) |
90 | cgit_index_link(fmt("[%d]", i+1), fmt("Page %d", i+1), NULL, | 90 | cgit_index_link(fmt("[%d]", i+1), fmt("Page %d", i+1), NULL, |
91 | search, i * pagelen); | 91 | search, i * pagelen); |
92 | html("</div>"); | 92 | html("</div>"); |
93 | } | 93 | } |
94 | 94 | ||
95 | void cgit_print_repolist() | 95 | void cgit_print_repolist() |
96 | { | 96 | { |
97 | int i, columns = 4, hits = 0, header = 0; | 97 | int i, columns = 4, hits = 0, header = 0; |
98 | char *last_group = NULL; | 98 | char *last_group = NULL; |
99 | 99 | ||
100 | if (ctx.cfg.enable_index_links) | 100 | if (ctx.cfg.enable_index_links) |
101 | columns++; | 101 | columns++; |
102 | 102 | ||
103 | ctx.page.title = ctx.cfg.root_title; | 103 | ctx.page.title = ctx.cfg.root_title; |
104 | cgit_print_http_headers(&ctx); | 104 | cgit_print_http_headers(&ctx); |
105 | cgit_print_docstart(&ctx); | 105 | cgit_print_docstart(&ctx); |
106 | cgit_print_pageheader(&ctx); | 106 | cgit_print_pageheader(&ctx); |
107 | 107 | ||
108 | if (ctx.cfg.index_header) | 108 | if (ctx.cfg.index_header) |
109 | html_include(ctx.cfg.index_header); | 109 | html_include(ctx.cfg.index_header); |
110 | 110 | ||
111 | html("<table summary='repository list' class='list nowrap'>"); | 111 | html("<table summary='repository list' class='list nowrap'>"); |
112 | for (i=0; i<cgit_repolist.count; i++) { | 112 | for (i=0; i<cgit_repolist.count; i++) { |
113 | ctx.repo = &cgit_repolist.repos[i]; | 113 | ctx.repo = &cgit_repolist.repos[i]; |
114 | if (!(is_match(ctx.repo) && is_in_url(ctx.repo))) | 114 | if (!(is_match(ctx.repo) && is_in_url(ctx.repo))) |
115 | continue; | 115 | continue; |
116 | hits++; | 116 | hits++; |
117 | if (hits <= ctx.qry.ofs) | 117 | if (hits <= ctx.qry.ofs) |
118 | continue; | 118 | continue; |
119 | if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count) | 119 | if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count) |
120 | continue; | 120 | continue; |
121 | if (!header++) | 121 | if (!header++) |
122 | print_header(columns); | 122 | print_header(columns); |
123 | if ((last_group == NULL && ctx.repo->group != NULL) || | 123 | if ((last_group == NULL && ctx.repo->group != NULL) || |
124 | (last_group != NULL && ctx.repo->group == NULL) || | 124 | (last_group != NULL && ctx.repo->group == NULL) || |
125 | (last_group != NULL && ctx.repo->group != NULL && | 125 | (last_group != NULL && ctx.repo->group != NULL && |
126 | strcmp(ctx.repo->group, last_group))) { | 126 | strcmp(ctx.repo->group, last_group))) { |
127 | htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>", | 127 | htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>", |
128 | columns); | 128 | columns); |
129 | html_txt(ctx.repo->group); | 129 | html_txt(ctx.repo->group); |
130 | html("</td></tr>"); | 130 | html("</td></tr>"); |
131 | last_group = ctx.repo->group; | 131 | last_group = ctx.repo->group; |
132 | } | 132 | } |
133 | htmlf("<tr><td class='%s'>", | 133 | htmlf("<tr><td class='%s'>", |
134 | ctx.repo->group ? "sublevel-repo" : "toplevel-repo"); | 134 | ctx.repo->group ? "sublevel-repo" : "toplevel-repo"); |
135 | cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); | 135 | cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); |
136 | html("</td><td>"); | 136 | html("</td><td>"); |
137 | html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL); | 137 | html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL); |
138 | html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc); | 138 | html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc); |
139 | html_link_close(); | 139 | html_link_close(); |
140 | html("</td><td>"); | 140 | html("</td><td>"); |
141 | html_txt(ctx.repo->owner); | 141 | html_txt(ctx.repo->owner); |
142 | html("</td><td>"); | 142 | html("</td><td>"); |
143 | print_modtime(ctx.repo); | 143 | print_modtime(ctx.repo); |
144 | html("</td>"); | 144 | html("</td>"); |
145 | if (ctx.cfg.enable_index_links) { | 145 | if (ctx.cfg.enable_index_links) { |
146 | html("<td>"); | 146 | html("<td>"); |
147 | cgit_summary_link("summary", NULL, "button", NULL); | 147 | cgit_summary_link("summary", NULL, "button", NULL); |
148 | cgit_log_link("log", NULL, "button", NULL, NULL, NULL, | 148 | cgit_log_link("log", NULL, "button", NULL, NULL, NULL, |
149 | 0, NULL, NULL); | 149 | 0, NULL, NULL, ctx.qry.showmsg); |
150 | cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); | 150 | cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); |
151 | html("</td>"); | 151 | html("</td>"); |
152 | } | 152 | } |
153 | html("</tr>\n"); | 153 | html("</tr>\n"); |
154 | } | 154 | } |
155 | html("</table>"); | 155 | html("</table>"); |
156 | if (!hits) | 156 | if (!hits) |
157 | cgit_print_error("No repositories found"); | 157 | cgit_print_error("No repositories found"); |
158 | else if (hits > ctx.cfg.max_repo_count) | 158 | else if (hits > ctx.cfg.max_repo_count) |
159 | print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search); | 159 | print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search); |
160 | cgit_print_docend(); | 160 | cgit_print_docend(); |
161 | } | 161 | } |
162 | 162 | ||
163 | void cgit_print_site_readme() | 163 | void cgit_print_site_readme() |
164 | { | 164 | { |
165 | if (ctx.cfg.root_readme) | 165 | if (ctx.cfg.root_readme) |
166 | html_include(ctx.cfg.root_readme); | 166 | html_include(ctx.cfg.root_readme); |
167 | } | 167 | } |
diff --git a/ui-shared.c b/ui-shared.c index 224e5f3..dc39e64 100644 --- a/ui-shared.c +++ b/ui-shared.c | |||
@@ -188,216 +188,222 @@ void cgit_index_link(char *name, char *title, char *class, char *pattern, | |||
188 | site_link(NULL, name, title, class, pattern, ofs); | 188 | site_link(NULL, name, title, class, pattern, ofs); |
189 | } | 189 | } |
190 | 190 | ||
191 | static char *repolink(char *title, char *class, char *page, char *head, | 191 | static char *repolink(char *title, char *class, char *page, char *head, |
192 | char *path) | 192 | char *path) |
193 | { | 193 | { |
194 | char *delim = "?"; | 194 | char *delim = "?"; |
195 | 195 | ||
196 | html("<a"); | 196 | html("<a"); |
197 | if (title) { | 197 | if (title) { |
198 | html(" title='"); | 198 | html(" title='"); |
199 | html_attr(title); | 199 | html_attr(title); |
200 | html("'"); | 200 | html("'"); |
201 | } | 201 | } |
202 | if (class) { | 202 | if (class) { |
203 | html(" class='"); | 203 | html(" class='"); |
204 | html_attr(class); | 204 | html_attr(class); |
205 | html("'"); | 205 | html("'"); |
206 | } | 206 | } |
207 | html(" href='"); | 207 | html(" href='"); |
208 | if (ctx.cfg.virtual_root) { | 208 | if (ctx.cfg.virtual_root) { |
209 | html_url_path(ctx.cfg.virtual_root); | 209 | html_url_path(ctx.cfg.virtual_root); |
210 | if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/') | 210 | if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/') |
211 | html("/"); | 211 | html("/"); |
212 | html_url_path(ctx.repo->url); | 212 | html_url_path(ctx.repo->url); |
213 | if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') | 213 | if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') |
214 | html("/"); | 214 | html("/"); |
215 | if (page) { | 215 | if (page) { |
216 | html_url_path(page); | 216 | html_url_path(page); |
217 | html("/"); | 217 | html("/"); |
218 | if (path) | 218 | if (path) |
219 | html_url_path(path); | 219 | html_url_path(path); |
220 | } | 220 | } |
221 | } else { | 221 | } else { |
222 | html(ctx.cfg.script_name); | 222 | html(ctx.cfg.script_name); |
223 | html("?url="); | 223 | html("?url="); |
224 | html_url_arg(ctx.repo->url); | 224 | html_url_arg(ctx.repo->url); |
225 | if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') | 225 | if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') |
226 | html("/"); | 226 | html("/"); |
227 | if (page) { | 227 | if (page) { |
228 | html_url_arg(page); | 228 | html_url_arg(page); |
229 | html("/"); | 229 | html("/"); |
230 | if (path) | 230 | if (path) |
231 | html_url_arg(path); | 231 | html_url_arg(path); |
232 | } | 232 | } |
233 | delim = "&"; | 233 | delim = "&"; |
234 | } | 234 | } |
235 | if (head && strcmp(head, ctx.repo->defbranch)) { | 235 | if (head && strcmp(head, ctx.repo->defbranch)) { |
236 | html(delim); | 236 | html(delim); |
237 | html("h="); | 237 | html("h="); |
238 | html_url_arg(head); | 238 | html_url_arg(head); |
239 | delim = "&"; | 239 | delim = "&"; |
240 | } | 240 | } |
241 | return fmt("%s", delim); | 241 | return fmt("%s", delim); |
242 | } | 242 | } |
243 | 243 | ||
244 | static void reporevlink(char *page, char *name, char *title, char *class, | 244 | static void reporevlink(char *page, char *name, char *title, char *class, |
245 | char *head, char *rev, char *path) | 245 | char *head, char *rev, char *path) |
246 | { | 246 | { |
247 | char *delim; | 247 | char *delim; |
248 | 248 | ||
249 | delim = repolink(title, class, page, head, path); | 249 | delim = repolink(title, class, page, head, path); |
250 | if (rev && strcmp(rev, ctx.qry.head)) { | 250 | if (rev && strcmp(rev, ctx.qry.head)) { |
251 | html(delim); | 251 | html(delim); |
252 | html("id="); | 252 | html("id="); |
253 | html_url_arg(rev); | 253 | html_url_arg(rev); |
254 | } | 254 | } |
255 | html("'>"); | 255 | html("'>"); |
256 | html_txt(name); | 256 | html_txt(name); |
257 | html("</a>"); | 257 | html("</a>"); |
258 | } | 258 | } |
259 | 259 | ||
260 | void cgit_summary_link(char *name, char *title, char *class, char *head) | 260 | void cgit_summary_link(char *name, char *title, char *class, char *head) |
261 | { | 261 | { |
262 | reporevlink(NULL, name, title, class, head, NULL, NULL); | 262 | reporevlink(NULL, name, title, class, head, NULL, NULL); |
263 | } | 263 | } |
264 | 264 | ||
265 | void cgit_tag_link(char *name, char *title, char *class, char *head, | 265 | void cgit_tag_link(char *name, char *title, char *class, char *head, |
266 | char *rev) | 266 | char *rev) |
267 | { | 267 | { |
268 | reporevlink("tag", name, title, class, head, rev, NULL); | 268 | reporevlink("tag", name, title, class, head, rev, NULL); |
269 | } | 269 | } |
270 | 270 | ||
271 | void cgit_tree_link(char *name, char *title, char *class, char *head, | 271 | void cgit_tree_link(char *name, char *title, char *class, char *head, |
272 | char *rev, char *path) | 272 | char *rev, char *path) |
273 | { | 273 | { |
274 | reporevlink("tree", name, title, class, head, rev, path); | 274 | reporevlink("tree", name, title, class, head, rev, path); |
275 | } | 275 | } |
276 | 276 | ||
277 | void cgit_plain_link(char *name, char *title, char *class, char *head, | 277 | void cgit_plain_link(char *name, char *title, char *class, char *head, |
278 | char *rev, char *path) | 278 | char *rev, char *path) |
279 | { | 279 | { |
280 | reporevlink("plain", name, title, class, head, rev, path); | 280 | reporevlink("plain", name, title, class, head, rev, path); |
281 | } | 281 | } |
282 | 282 | ||
283 | void cgit_log_link(char *name, char *title, char *class, char *head, | 283 | void cgit_log_link(char *name, char *title, char *class, char *head, |
284 | char *rev, char *path, int ofs, char *grep, char *pattern) | 284 | char *rev, char *path, int ofs, char *grep, char *pattern, |
285 | int showmsg) | ||
285 | { | 286 | { |
286 | char *delim; | 287 | char *delim; |
287 | 288 | ||
288 | delim = repolink(title, class, "log", head, path); | 289 | delim = repolink(title, class, "log", head, path); |
289 | if (rev && strcmp(rev, ctx.qry.head)) { | 290 | if (rev && strcmp(rev, ctx.qry.head)) { |
290 | html(delim); | 291 | html(delim); |
291 | html("id="); | 292 | html("id="); |
292 | html_url_arg(rev); | 293 | html_url_arg(rev); |
293 | delim = "&"; | 294 | delim = "&"; |
294 | } | 295 | } |
295 | if (grep && pattern) { | 296 | if (grep && pattern) { |
296 | html(delim); | 297 | html(delim); |
297 | html("qt="); | 298 | html("qt="); |
298 | html_url_arg(grep); | 299 | html_url_arg(grep); |
299 | delim = "&"; | 300 | delim = "&"; |
300 | html(delim); | 301 | html(delim); |
301 | html("q="); | 302 | html("q="); |
302 | html_url_arg(pattern); | 303 | html_url_arg(pattern); |
303 | } | 304 | } |
304 | if (ofs > 0) { | 305 | if (ofs > 0) { |
305 | html(delim); | 306 | html(delim); |
306 | html("ofs="); | 307 | html("ofs="); |
307 | htmlf("%d", ofs); | 308 | htmlf("%d", ofs); |
309 | delim = "&"; | ||
310 | } | ||
311 | if (showmsg) { | ||
312 | html(delim); | ||
313 | html("showmsg=1"); | ||
308 | } | 314 | } |
309 | html("'>"); | 315 | html("'>"); |
310 | html_txt(name); | 316 | html_txt(name); |
311 | html("</a>"); | 317 | html("</a>"); |
312 | } | 318 | } |
313 | 319 | ||
314 | void cgit_commit_link(char *name, char *title, char *class, char *head, | 320 | void cgit_commit_link(char *name, char *title, char *class, char *head, |
315 | char *rev) | 321 | char *rev) |
316 | { | 322 | { |
317 | if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { | 323 | if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { |
318 | name[ctx.cfg.max_msg_len] = '\0'; | 324 | name[ctx.cfg.max_msg_len] = '\0'; |
319 | name[ctx.cfg.max_msg_len - 1] = '.'; | 325 | name[ctx.cfg.max_msg_len - 1] = '.'; |
320 | name[ctx.cfg.max_msg_len - 2] = '.'; | 326 | name[ctx.cfg.max_msg_len - 2] = '.'; |
321 | name[ctx.cfg.max_msg_len - 3] = '.'; | 327 | name[ctx.cfg.max_msg_len - 3] = '.'; |
322 | } | 328 | } |
323 | reporevlink("commit", name, title, class, head, rev, NULL); | 329 | reporevlink("commit", name, title, class, head, rev, NULL); |
324 | } | 330 | } |
325 | 331 | ||
326 | void cgit_refs_link(char *name, char *title, char *class, char *head, | 332 | void cgit_refs_link(char *name, char *title, char *class, char *head, |
327 | char *rev, char *path) | 333 | char *rev, char *path) |
328 | { | 334 | { |
329 | reporevlink("refs", name, title, class, head, rev, path); | 335 | reporevlink("refs", name, title, class, head, rev, path); |
330 | } | 336 | } |
331 | 337 | ||
332 | void cgit_snapshot_link(char *name, char *title, char *class, char *head, | 338 | void cgit_snapshot_link(char *name, char *title, char *class, char *head, |
333 | char *rev, char *archivename) | 339 | char *rev, char *archivename) |
334 | { | 340 | { |
335 | reporevlink("snapshot", name, title, class, head, rev, archivename); | 341 | reporevlink("snapshot", name, title, class, head, rev, archivename); |
336 | } | 342 | } |
337 | 343 | ||
338 | void cgit_diff_link(char *name, char *title, char *class, char *head, | 344 | void cgit_diff_link(char *name, char *title, char *class, char *head, |
339 | char *new_rev, char *old_rev, char *path) | 345 | char *new_rev, char *old_rev, char *path) |
340 | { | 346 | { |
341 | char *delim; | 347 | char *delim; |
342 | 348 | ||
343 | delim = repolink(title, class, "diff", head, path); | 349 | delim = repolink(title, class, "diff", head, path); |
344 | if (new_rev && strcmp(new_rev, ctx.qry.head)) { | 350 | if (new_rev && strcmp(new_rev, ctx.qry.head)) { |
345 | html(delim); | 351 | html(delim); |
346 | html("id="); | 352 | html("id="); |
347 | html_url_arg(new_rev); | 353 | html_url_arg(new_rev); |
348 | delim = "&"; | 354 | delim = "&"; |
349 | } | 355 | } |
350 | if (old_rev) { | 356 | if (old_rev) { |
351 | html(delim); | 357 | html(delim); |
352 | html("id2="); | 358 | html("id2="); |
353 | html_url_arg(old_rev); | 359 | html_url_arg(old_rev); |
354 | } | 360 | } |
355 | html("'>"); | 361 | html("'>"); |
356 | html_txt(name); | 362 | html_txt(name); |
357 | html("</a>"); | 363 | html("</a>"); |
358 | } | 364 | } |
359 | 365 | ||
360 | void cgit_patch_link(char *name, char *title, char *class, char *head, | 366 | void cgit_patch_link(char *name, char *title, char *class, char *head, |
361 | char *rev) | 367 | char *rev) |
362 | { | 368 | { |
363 | reporevlink("patch", name, title, class, head, rev, NULL); | 369 | reporevlink("patch", name, title, class, head, rev, NULL); |
364 | } | 370 | } |
365 | 371 | ||
366 | void cgit_object_link(struct object *obj) | 372 | void cgit_object_link(struct object *obj) |
367 | { | 373 | { |
368 | char *page, *rev, *name; | 374 | char *page, *rev, *name; |
369 | 375 | ||
370 | if (obj->type == OBJ_COMMIT) { | 376 | if (obj->type == OBJ_COMMIT) { |
371 | cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL, | 377 | cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL, |
372 | ctx.qry.head, sha1_to_hex(obj->sha1)); | 378 | ctx.qry.head, sha1_to_hex(obj->sha1)); |
373 | return; | 379 | return; |
374 | } else if (obj->type == OBJ_TREE) | 380 | } else if (obj->type == OBJ_TREE) |
375 | page = "tree"; | 381 | page = "tree"; |
376 | else if (obj->type == OBJ_TAG) | 382 | else if (obj->type == OBJ_TAG) |
377 | page = "tag"; | 383 | page = "tag"; |
378 | else | 384 | else |
379 | page = "blob"; | 385 | page = "blob"; |
380 | rev = sha1_to_hex(obj->sha1); | 386 | rev = sha1_to_hex(obj->sha1); |
381 | name = fmt("%s %s", typename(obj->type), rev); | 387 | name = fmt("%s %s", typename(obj->type), rev); |
382 | reporevlink(page, name, NULL, NULL, ctx.qry.head, rev, NULL); | 388 | reporevlink(page, name, NULL, NULL, ctx.qry.head, rev, NULL); |
383 | } | 389 | } |
384 | 390 | ||
385 | void cgit_print_date(time_t secs, char *format, int local_time) | 391 | void cgit_print_date(time_t secs, char *format, int local_time) |
386 | { | 392 | { |
387 | char buf[64]; | 393 | char buf[64]; |
388 | struct tm *time; | 394 | struct tm *time; |
389 | 395 | ||
390 | if (!secs) | 396 | if (!secs) |
391 | return; | 397 | return; |
392 | if(local_time) | 398 | if(local_time) |
393 | time = localtime(&secs); | 399 | time = localtime(&secs); |
394 | else | 400 | else |
395 | time = gmtime(&secs); | 401 | time = gmtime(&secs); |
396 | strftime(buf, sizeof(buf)-1, format, time); | 402 | strftime(buf, sizeof(buf)-1, format, time); |
397 | html_txt(buf); | 403 | html_txt(buf); |
398 | } | 404 | } |
399 | 405 | ||
400 | void cgit_print_age(time_t t, time_t max_relative, char *format) | 406 | void cgit_print_age(time_t t, time_t max_relative, char *format) |
401 | { | 407 | { |
402 | time_t now, secs; | 408 | time_t now, secs; |
403 | 409 | ||
@@ -475,240 +481,242 @@ void cgit_print_docstart(struct cgit_context *ctx) | |||
475 | if (ctx->cfg.favicon) { | 481 | if (ctx->cfg.favicon) { |
476 | html("<link rel='shortcut icon' href='"); | 482 | html("<link rel='shortcut icon' href='"); |
477 | html_attr(ctx->cfg.favicon); | 483 | html_attr(ctx->cfg.favicon); |
478 | html("'/>\n"); | 484 | html("'/>\n"); |
479 | } | 485 | } |
480 | if (host && ctx->repo) { | 486 | if (host && ctx->repo) { |
481 | html("<link rel='alternate' title='Atom feed' href='http://"); | 487 | html("<link rel='alternate' title='Atom feed' href='http://"); |
482 | html_attr(cgit_hosturl()); | 488 | html_attr(cgit_hosturl()); |
483 | html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.path, | 489 | html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.path, |
484 | fmt("h=%s", ctx->qry.head))); | 490 | fmt("h=%s", ctx->qry.head))); |
485 | html("' type='application/atom+xml'/>"); | 491 | html("' type='application/atom+xml'/>"); |
486 | } | 492 | } |
487 | html("</head>\n"); | 493 | html("</head>\n"); |
488 | html("<body>\n"); | 494 | html("<body>\n"); |
489 | } | 495 | } |
490 | 496 | ||
491 | void cgit_print_docend() | 497 | void cgit_print_docend() |
492 | { | 498 | { |
493 | html("</div>"); | 499 | html("</div>"); |
494 | if (ctx.cfg.footer) | 500 | if (ctx.cfg.footer) |
495 | html_include(ctx.cfg.footer); | 501 | html_include(ctx.cfg.footer); |
496 | else { | 502 | else { |
497 | htmlf("<div class='footer'>generated by cgit %s at ", | 503 | htmlf("<div class='footer'>generated by cgit %s at ", |
498 | cgit_version); | 504 | cgit_version); |
499 | cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time); | 505 | cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time); |
500 | html("</div>\n"); | 506 | html("</div>\n"); |
501 | } | 507 | } |
502 | html("</body>\n</html>\n"); | 508 | html("</body>\n</html>\n"); |
503 | } | 509 | } |
504 | 510 | ||
505 | int print_branch_option(const char *refname, const unsigned char *sha1, | 511 | int print_branch_option(const char *refname, const unsigned char *sha1, |
506 | int flags, void *cb_data) | 512 | int flags, void *cb_data) |
507 | { | 513 | { |
508 | char *name = (char *)refname; | 514 | char *name = (char *)refname; |
509 | html_option(name, name, ctx.qry.head); | 515 | html_option(name, name, ctx.qry.head); |
510 | return 0; | 516 | return 0; |
511 | } | 517 | } |
512 | 518 | ||
513 | int print_archive_ref(const char *refname, const unsigned char *sha1, | 519 | int print_archive_ref(const char *refname, const unsigned char *sha1, |
514 | int flags, void *cb_data) | 520 | int flags, void *cb_data) |
515 | { | 521 | { |
516 | struct tag *tag; | 522 | struct tag *tag; |
517 | struct taginfo *info; | 523 | struct taginfo *info; |
518 | struct object *obj; | 524 | struct object *obj; |
519 | char buf[256], *url; | 525 | char buf[256], *url; |
520 | unsigned char fileid[20]; | 526 | unsigned char fileid[20]; |
521 | int *header = (int *)cb_data; | 527 | int *header = (int *)cb_data; |
522 | 528 | ||
523 | if (prefixcmp(refname, "refs/archives")) | 529 | if (prefixcmp(refname, "refs/archives")) |
524 | return 0; | 530 | return 0; |
525 | strncpy(buf, refname+14, sizeof(buf)); | 531 | strncpy(buf, refname+14, sizeof(buf)); |
526 | obj = parse_object(sha1); | 532 | obj = parse_object(sha1); |
527 | if (!obj) | 533 | if (!obj) |
528 | return 1; | 534 | return 1; |
529 | if (obj->type == OBJ_TAG) { | 535 | if (obj->type == OBJ_TAG) { |
530 | tag = lookup_tag(sha1); | 536 | tag = lookup_tag(sha1); |
531 | if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) | 537 | if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) |
532 | return 0; | 538 | return 0; |
533 | hashcpy(fileid, tag->tagged->sha1); | 539 | hashcpy(fileid, tag->tagged->sha1); |
534 | } else if (obj->type != OBJ_BLOB) { | 540 | } else if (obj->type != OBJ_BLOB) { |
535 | return 0; | 541 | return 0; |
536 | } else { | 542 | } else { |
537 | hashcpy(fileid, sha1); | 543 | hashcpy(fileid, sha1); |
538 | } | 544 | } |
539 | if (!*header) { | 545 | if (!*header) { |
540 | html("<h1>download</h1>\n"); | 546 | html("<h1>download</h1>\n"); |
541 | *header = 1; | 547 | *header = 1; |
542 | } | 548 | } |
543 | url = cgit_pageurl(ctx.qry.repo, "blob", | 549 | url = cgit_pageurl(ctx.qry.repo, "blob", |
544 | fmt("id=%s&path=%s", sha1_to_hex(fileid), | 550 | fmt("id=%s&path=%s", sha1_to_hex(fileid), |
545 | buf)); | 551 | buf)); |
546 | html_link_open(url, NULL, "menu"); | 552 | html_link_open(url, NULL, "menu"); |
547 | html_txt(strlpart(buf, 20)); | 553 | html_txt(strlpart(buf, 20)); |
548 | html_link_close(); | 554 | html_link_close(); |
549 | return 0; | 555 | return 0; |
550 | } | 556 | } |
551 | 557 | ||
552 | void add_hidden_formfields(int incl_head, int incl_search, char *page) | 558 | void add_hidden_formfields(int incl_head, int incl_search, char *page) |
553 | { | 559 | { |
554 | char *url; | 560 | char *url; |
555 | 561 | ||
556 | if (!ctx.cfg.virtual_root) { | 562 | if (!ctx.cfg.virtual_root) { |
557 | url = fmt("%s/%s", ctx.qry.repo, page); | 563 | url = fmt("%s/%s", ctx.qry.repo, page); |
558 | if (ctx.qry.path) | 564 | if (ctx.qry.path) |
559 | url = fmt("%s/%s", url, ctx.qry.path); | 565 | url = fmt("%s/%s", url, ctx.qry.path); |
560 | html_hidden("url", url); | 566 | html_hidden("url", url); |
561 | } | 567 | } |
562 | 568 | ||
563 | if (incl_head && ctx.qry.head && ctx.repo->defbranch && | 569 | if (incl_head && ctx.qry.head && ctx.repo->defbranch && |
564 | strcmp(ctx.qry.head, ctx.repo->defbranch)) | 570 | strcmp(ctx.qry.head, ctx.repo->defbranch)) |
565 | html_hidden("h", ctx.qry.head); | 571 | html_hidden("h", ctx.qry.head); |
566 | 572 | ||
567 | if (ctx.qry.sha1) | 573 | if (ctx.qry.sha1) |
568 | html_hidden("id", ctx.qry.sha1); | 574 | html_hidden("id", ctx.qry.sha1); |
569 | if (ctx.qry.sha2) | 575 | if (ctx.qry.sha2) |
570 | html_hidden("id2", ctx.qry.sha2); | 576 | html_hidden("id2", ctx.qry.sha2); |
577 | if (ctx.qry.showmsg) | ||
578 | html_hidden("showmsg", "1"); | ||
571 | 579 | ||
572 | if (incl_search) { | 580 | if (incl_search) { |
573 | if (ctx.qry.grep) | 581 | if (ctx.qry.grep) |
574 | html_hidden("qt", ctx.qry.grep); | 582 | html_hidden("qt", ctx.qry.grep); |
575 | if (ctx.qry.search) | 583 | if (ctx.qry.search) |
576 | html_hidden("q", ctx.qry.search); | 584 | html_hidden("q", ctx.qry.search); |
577 | } | 585 | } |
578 | } | 586 | } |
579 | 587 | ||
580 | char *hc(struct cgit_cmd *cmd, const char *page) | 588 | char *hc(struct cgit_cmd *cmd, const char *page) |
581 | { | 589 | { |
582 | return (strcmp(cmd->name, page) ? NULL : "active"); | 590 | return (strcmp(cmd->name, page) ? NULL : "active"); |
583 | } | 591 | } |
584 | 592 | ||
585 | void cgit_print_pageheader(struct cgit_context *ctx) | 593 | void cgit_print_pageheader(struct cgit_context *ctx) |
586 | { | 594 | { |
587 | struct cgit_cmd *cmd = cgit_get_cmd(ctx); | 595 | struct cgit_cmd *cmd = cgit_get_cmd(ctx); |
588 | 596 | ||
589 | html("<table id='header'>\n"); | 597 | html("<table id='header'>\n"); |
590 | html("<tr>\n"); | 598 | html("<tr>\n"); |
591 | html("<td class='logo' rowspan='2'><a href='"); | 599 | html("<td class='logo' rowspan='2'><a href='"); |
592 | if (ctx->cfg.logo_link) | 600 | if (ctx->cfg.logo_link) |
593 | html_attr(ctx->cfg.logo_link); | 601 | html_attr(ctx->cfg.logo_link); |
594 | else | 602 | else |
595 | html_attr(cgit_rooturl()); | 603 | html_attr(cgit_rooturl()); |
596 | html("'><img src='"); | 604 | html("'><img src='"); |
597 | html_attr(ctx->cfg.logo); | 605 | html_attr(ctx->cfg.logo); |
598 | html("' alt='cgit logo'/></a></td>\n"); | 606 | html("' alt='cgit logo'/></a></td>\n"); |
599 | 607 | ||
600 | html("<td class='main'>"); | 608 | html("<td class='main'>"); |
601 | if (ctx->repo) { | 609 | if (ctx->repo) { |
602 | cgit_index_link("index", NULL, NULL, NULL, 0); | 610 | cgit_index_link("index", NULL, NULL, NULL, 0); |
603 | html(" : "); | 611 | html(" : "); |
604 | cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); | 612 | cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); |
605 | html("</td><td class='form'>"); | 613 | html("</td><td class='form'>"); |
606 | html("<form method='get' action=''>\n"); | 614 | html("<form method='get' action=''>\n"); |
607 | add_hidden_formfields(0, 1, ctx->qry.page); | 615 | add_hidden_formfields(0, 1, ctx->qry.page); |
608 | html("<select name='h' onchange='this.form.submit();'>\n"); | 616 | html("<select name='h' onchange='this.form.submit();'>\n"); |
609 | for_each_branch_ref(print_branch_option, ctx->qry.head); | 617 | for_each_branch_ref(print_branch_option, ctx->qry.head); |
610 | html("</select> "); | 618 | html("</select> "); |
611 | html("<input type='submit' name='' value='switch'/>"); | 619 | html("<input type='submit' name='' value='switch'/>"); |
612 | html("</form>"); | 620 | html("</form>"); |
613 | } else | 621 | } else |
614 | html_txt(ctx->cfg.root_title); | 622 | html_txt(ctx->cfg.root_title); |
615 | html("</td></tr>\n"); | 623 | html("</td></tr>\n"); |
616 | 624 | ||
617 | html("<tr><td class='sub'>"); | 625 | html("<tr><td class='sub'>"); |
618 | if (ctx->repo) { | 626 | if (ctx->repo) { |
619 | html_txt(ctx->repo->desc); | 627 | html_txt(ctx->repo->desc); |
620 | html("</td><td class='sub right'>"); | 628 | html("</td><td class='sub right'>"); |
621 | html_txt(ctx->repo->owner); | 629 | html_txt(ctx->repo->owner); |
622 | } else { | 630 | } else { |
623 | if (ctx->cfg.root_desc) | 631 | if (ctx->cfg.root_desc) |
624 | html_txt(ctx->cfg.root_desc); | 632 | html_txt(ctx->cfg.root_desc); |
625 | else if (ctx->cfg.index_info) | 633 | else if (ctx->cfg.index_info) |
626 | html_include(ctx->cfg.index_info); | 634 | html_include(ctx->cfg.index_info); |
627 | } | 635 | } |
628 | html("</td></tr></table>\n"); | 636 | html("</td></tr></table>\n"); |
629 | 637 | ||
630 | html("<table class='tabs'><tr><td>\n"); | 638 | html("<table class='tabs'><tr><td>\n"); |
631 | if (ctx->repo) { | 639 | if (ctx->repo) { |
632 | cgit_summary_link("summary", NULL, hc(cmd, "summary"), | 640 | cgit_summary_link("summary", NULL, hc(cmd, "summary"), |
633 | ctx->qry.head); | 641 | ctx->qry.head); |
634 | cgit_refs_link("refs", NULL, hc(cmd, "refs"), ctx->qry.head, | 642 | cgit_refs_link("refs", NULL, hc(cmd, "refs"), ctx->qry.head, |
635 | ctx->qry.sha1, NULL); | 643 | ctx->qry.sha1, NULL); |
636 | cgit_log_link("log", NULL, hc(cmd, "log"), ctx->qry.head, | 644 | cgit_log_link("log", NULL, hc(cmd, "log"), ctx->qry.head, |
637 | NULL, NULL, 0, NULL, NULL); | 645 | NULL, NULL, 0, NULL, NULL, ctx->qry.showmsg); |
638 | cgit_tree_link("tree", NULL, hc(cmd, "tree"), ctx->qry.head, | 646 | cgit_tree_link("tree", NULL, hc(cmd, "tree"), ctx->qry.head, |
639 | ctx->qry.sha1, NULL); | 647 | ctx->qry.sha1, NULL); |
640 | cgit_commit_link("commit", NULL, hc(cmd, "commit"), | 648 | cgit_commit_link("commit", NULL, hc(cmd, "commit"), |
641 | ctx->qry.head, ctx->qry.sha1); | 649 | ctx->qry.head, ctx->qry.sha1); |
642 | cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head, | 650 | cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head, |
643 | ctx->qry.sha1, ctx->qry.sha2, NULL); | 651 | ctx->qry.sha1, ctx->qry.sha2, NULL); |
644 | if (ctx->repo->readme) | 652 | if (ctx->repo->readme) |
645 | reporevlink("about", "about", NULL, | 653 | reporevlink("about", "about", NULL, |
646 | hc(cmd, "about"), ctx->qry.head, NULL, | 654 | hc(cmd, "about"), ctx->qry.head, NULL, |
647 | NULL); | 655 | NULL); |
648 | html("</td><td class='form'>"); | 656 | html("</td><td class='form'>"); |
649 | html("<form class='right' method='get' action='"); | 657 | html("<form class='right' method='get' action='"); |
650 | if (ctx->cfg.virtual_root) | 658 | if (ctx->cfg.virtual_root) |
651 | html_url_path(cgit_fileurl(ctx->qry.repo, "log", | 659 | html_url_path(cgit_fileurl(ctx->qry.repo, "log", |
652 | ctx->qry.path, NULL)); | 660 | ctx->qry.path, NULL)); |
653 | html("'>\n"); | 661 | html("'>\n"); |
654 | add_hidden_formfields(1, 0, "log"); | 662 | add_hidden_formfields(1, 0, "log"); |
655 | html("<select name='qt'>\n"); | 663 | html("<select name='qt'>\n"); |
656 | html_option("grep", "log msg", ctx->qry.grep); | 664 | html_option("grep", "log msg", ctx->qry.grep); |
657 | html_option("author", "author", ctx->qry.grep); | 665 | html_option("author", "author", ctx->qry.grep); |
658 | html_option("committer", "committer", ctx->qry.grep); | 666 | html_option("committer", "committer", ctx->qry.grep); |
659 | html("</select>\n"); | 667 | html("</select>\n"); |
660 | html("<input class='txt' type='text' size='10' name='q' value='"); | 668 | html("<input class='txt' type='text' size='10' name='q' value='"); |
661 | html_attr(ctx->qry.search); | 669 | html_attr(ctx->qry.search); |
662 | html("'/>\n"); | 670 | html("'/>\n"); |
663 | html("<input type='submit' value='search'/>\n"); | 671 | html("<input type='submit' value='search'/>\n"); |
664 | html("</form>\n"); | 672 | html("</form>\n"); |
665 | } else { | 673 | } else { |
666 | site_link(NULL, "index", NULL, hc(cmd, "repolist"), NULL, 0); | 674 | site_link(NULL, "index", NULL, hc(cmd, "repolist"), NULL, 0); |
667 | if (ctx->cfg.root_readme) | 675 | if (ctx->cfg.root_readme) |
668 | site_link("about", "about", NULL, hc(cmd, "about"), | 676 | site_link("about", "about", NULL, hc(cmd, "about"), |
669 | NULL, 0); | 677 | NULL, 0); |
670 | html("</td><td class='form'>"); | 678 | html("</td><td class='form'>"); |
671 | html("<form method='get' action='"); | 679 | html("<form method='get' action='"); |
672 | html_attr(cgit_rooturl()); | 680 | html_attr(cgit_rooturl()); |
673 | html("'>\n"); | 681 | html("'>\n"); |
674 | html("<input type='text' name='q' size='10' value='"); | 682 | html("<input type='text' name='q' size='10' value='"); |
675 | html_attr(ctx->qry.search); | 683 | html_attr(ctx->qry.search); |
676 | html("'/>\n"); | 684 | html("'/>\n"); |
677 | html("<input type='submit' value='search'/>\n"); | 685 | html("<input type='submit' value='search'/>\n"); |
678 | html("</form>"); | 686 | html("</form>"); |
679 | } | 687 | } |
680 | html("</td></tr></table>\n"); | 688 | html("</td></tr></table>\n"); |
681 | html("<div class='content'>"); | 689 | html("<div class='content'>"); |
682 | } | 690 | } |
683 | 691 | ||
684 | void cgit_print_filemode(unsigned short mode) | 692 | void cgit_print_filemode(unsigned short mode) |
685 | { | 693 | { |
686 | if (S_ISDIR(mode)) | 694 | if (S_ISDIR(mode)) |
687 | html("d"); | 695 | html("d"); |
688 | else if (S_ISLNK(mode)) | 696 | else if (S_ISLNK(mode)) |
689 | html("l"); | 697 | html("l"); |
690 | else if (S_ISGITLINK(mode)) | 698 | else if (S_ISGITLINK(mode)) |
691 | html("m"); | 699 | html("m"); |
692 | else | 700 | else |
693 | html("-"); | 701 | html("-"); |
694 | html_fileperm(mode >> 6); | 702 | html_fileperm(mode >> 6); |
695 | html_fileperm(mode >> 3); | 703 | html_fileperm(mode >> 3); |
696 | html_fileperm(mode); | 704 | html_fileperm(mode); |
697 | } | 705 | } |
698 | 706 | ||
699 | void cgit_print_snapshot_links(const char *repo, const char *head, | 707 | void cgit_print_snapshot_links(const char *repo, const char *head, |
700 | const char *hex, int snapshots) | 708 | const char *hex, int snapshots) |
701 | { | 709 | { |
702 | const struct cgit_snapshot_format* f; | 710 | const struct cgit_snapshot_format* f; |
703 | char *filename; | 711 | char *filename; |
704 | 712 | ||
705 | for (f = cgit_snapshot_formats; f->suffix; f++) { | 713 | for (f = cgit_snapshot_formats; f->suffix; f++) { |
706 | if (!(snapshots & f->bit)) | 714 | if (!(snapshots & f->bit)) |
707 | continue; | 715 | continue; |
708 | filename = fmt("%s-%s%s", cgit_repobasename(repo), hex, | 716 | filename = fmt("%s-%s%s", cgit_repobasename(repo), hex, |
709 | f->suffix); | 717 | f->suffix); |
710 | cgit_snapshot_link(filename, NULL, NULL, (char *)head, | 718 | cgit_snapshot_link(filename, NULL, NULL, (char *)head, |
711 | (char *)hex, filename); | 719 | (char *)hex, filename); |
712 | html("<br/>"); | 720 | html("<br/>"); |
713 | } | 721 | } |
714 | } | 722 | } |
diff --git a/ui-shared.h b/ui-shared.h index 3c8a6d0..2ab53ae 100644 --- a/ui-shared.h +++ b/ui-shared.h | |||
@@ -1,46 +1,46 @@ | |||
1 | #ifndef UI_SHARED_H | 1 | #ifndef UI_SHARED_H |
2 | #define UI_SHARED_H | 2 | #define UI_SHARED_H |
3 | 3 | ||
4 | extern char *cgit_hosturl(); | 4 | extern char *cgit_hosturl(); |
5 | extern char *cgit_repourl(const char *reponame); | 5 | extern char *cgit_repourl(const char *reponame); |
6 | extern char *cgit_fileurl(const char *reponame, const char *pagename, | 6 | extern char *cgit_fileurl(const char *reponame, const char *pagename, |
7 | const char *filename, const char *query); | 7 | const char *filename, const char *query); |
8 | extern char *cgit_pageurl(const char *reponame, const char *pagename, | 8 | extern char *cgit_pageurl(const char *reponame, const char *pagename, |
9 | const char *query); | 9 | const char *query); |
10 | 10 | ||
11 | extern void cgit_index_link(char *name, char *title, char *class, | 11 | extern void cgit_index_link(char *name, char *title, char *class, |
12 | char *pattern, int ofs); | 12 | char *pattern, int ofs); |
13 | extern void cgit_summary_link(char *name, char *title, char *class, char *head); | 13 | extern void cgit_summary_link(char *name, char *title, char *class, char *head); |
14 | extern void cgit_tag_link(char *name, char *title, char *class, char *head, | 14 | extern void cgit_tag_link(char *name, char *title, char *class, char *head, |
15 | char *rev); | 15 | char *rev); |
16 | extern void cgit_tree_link(char *name, char *title, char *class, char *head, | 16 | extern void cgit_tree_link(char *name, char *title, char *class, char *head, |
17 | char *rev, char *path); | 17 | char *rev, char *path); |
18 | extern void cgit_plain_link(char *name, char *title, char *class, char *head, | 18 | extern void cgit_plain_link(char *name, char *title, char *class, char *head, |
19 | char *rev, char *path); | 19 | char *rev, char *path); |
20 | extern void cgit_log_link(char *name, char *title, char *class, char *head, | 20 | extern void cgit_log_link(char *name, char *title, char *class, char *head, |
21 | char *rev, char *path, int ofs, char *grep, | 21 | char *rev, char *path, int ofs, char *grep, |
22 | char *pattern); | 22 | char *pattern, int showmsg); |
23 | extern void cgit_commit_link(char *name, char *title, char *class, char *head, | 23 | extern void cgit_commit_link(char *name, char *title, char *class, char *head, |
24 | char *rev); | 24 | char *rev); |
25 | extern void cgit_patch_link(char *name, char *title, char *class, char *head, | 25 | extern void cgit_patch_link(char *name, char *title, char *class, char *head, |
26 | char *rev); | 26 | char *rev); |
27 | extern void cgit_refs_link(char *name, char *title, char *class, char *head, | 27 | extern void cgit_refs_link(char *name, char *title, char *class, char *head, |
28 | char *rev, char *path); | 28 | char *rev, char *path); |
29 | extern void cgit_snapshot_link(char *name, char *title, char *class, | 29 | extern void cgit_snapshot_link(char *name, char *title, char *class, |
30 | char *head, char *rev, char *archivename); | 30 | char *head, char *rev, char *archivename); |
31 | extern void cgit_diff_link(char *name, char *title, char *class, char *head, | 31 | extern void cgit_diff_link(char *name, char *title, char *class, char *head, |
32 | char *new_rev, char *old_rev, char *path); | 32 | char *new_rev, char *old_rev, char *path); |
33 | extern void cgit_object_link(struct object *obj); | 33 | extern void cgit_object_link(struct object *obj); |
34 | 34 | ||
35 | extern void cgit_print_error(char *msg); | 35 | extern void cgit_print_error(char *msg); |
36 | extern void cgit_print_date(time_t secs, char *format, int local_time); | 36 | extern void cgit_print_date(time_t secs, char *format, int local_time); |
37 | extern void cgit_print_age(time_t t, time_t max_relative, char *format); | 37 | extern void cgit_print_age(time_t t, time_t max_relative, char *format); |
38 | extern void cgit_print_http_headers(struct cgit_context *ctx); | 38 | extern void cgit_print_http_headers(struct cgit_context *ctx); |
39 | extern void cgit_print_docstart(struct cgit_context *ctx); | 39 | extern void cgit_print_docstart(struct cgit_context *ctx); |
40 | extern void cgit_print_docend(); | 40 | extern void cgit_print_docend(); |
41 | extern void cgit_print_pageheader(struct cgit_context *ctx); | 41 | extern void cgit_print_pageheader(struct cgit_context *ctx); |
42 | extern void cgit_print_filemode(unsigned short mode); | 42 | extern void cgit_print_filemode(unsigned short mode); |
43 | extern void cgit_print_snapshot_links(const char *repo, const char *head, | 43 | extern void cgit_print_snapshot_links(const char *repo, const char *head, |
44 | const char *hex, int snapshots); | 44 | const char *hex, int snapshots); |
45 | 45 | ||
46 | #endif /* UI_SHARED_H */ | 46 | #endif /* UI_SHARED_H */ |
@@ -13,193 +13,193 @@ | |||
13 | char *curr_rev; | 13 | char *curr_rev; |
14 | char *match_path; | 14 | char *match_path; |
15 | int header = 0; | 15 | int header = 0; |
16 | 16 | ||
17 | static void print_object(const unsigned char *sha1, char *path) | 17 | static void print_object(const unsigned char *sha1, char *path) |
18 | { | 18 | { |
19 | enum object_type type; | 19 | enum object_type type; |
20 | char *buf; | 20 | char *buf; |
21 | unsigned long size, lineno, start, idx; | 21 | unsigned long size, lineno, start, idx; |
22 | const char *linefmt = "<tr><td class='no'><a id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a></td><td class='txt'>"; | 22 | const char *linefmt = "<tr><td class='no'><a id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a></td><td class='txt'>"; |
23 | 23 | ||
24 | type = sha1_object_info(sha1, &size); | 24 | type = sha1_object_info(sha1, &size); |
25 | if (type == OBJ_BAD) { | 25 | if (type == OBJ_BAD) { |
26 | cgit_print_error(fmt("Bad object name: %s", | 26 | cgit_print_error(fmt("Bad object name: %s", |
27 | sha1_to_hex(sha1))); | 27 | sha1_to_hex(sha1))); |
28 | return; | 28 | return; |
29 | } | 29 | } |
30 | 30 | ||
31 | buf = read_sha1_file(sha1, &type, &size); | 31 | buf = read_sha1_file(sha1, &type, &size); |
32 | if (!buf) { | 32 | if (!buf) { |
33 | cgit_print_error(fmt("Error reading object %s", | 33 | cgit_print_error(fmt("Error reading object %s", |
34 | sha1_to_hex(sha1))); | 34 | sha1_to_hex(sha1))); |
35 | return; | 35 | return; |
36 | } | 36 | } |
37 | 37 | ||
38 | html(" ("); | 38 | html(" ("); |
39 | cgit_plain_link("plain", NULL, NULL, ctx.qry.head, | 39 | cgit_plain_link("plain", NULL, NULL, ctx.qry.head, |
40 | curr_rev, path); | 40 | curr_rev, path); |
41 | htmlf(")<br/>blob: %s", sha1_to_hex(sha1)); | 41 | htmlf(")<br/>blob: %s", sha1_to_hex(sha1)); |
42 | 42 | ||
43 | html("<table summary='blob content' class='blob'>\n"); | 43 | html("<table summary='blob content' class='blob'>\n"); |
44 | idx = 0; | 44 | idx = 0; |
45 | start = 0; | 45 | start = 0; |
46 | lineno = 0; | 46 | lineno = 0; |
47 | while(idx < size) { | 47 | while(idx < size) { |
48 | if (buf[idx] == '\n') { | 48 | if (buf[idx] == '\n') { |
49 | buf[idx] = '\0'; | 49 | buf[idx] = '\0'; |
50 | htmlf(linefmt, ++lineno); | 50 | htmlf(linefmt, ++lineno); |
51 | html_txt(buf + start); | 51 | html_txt(buf + start); |
52 | html("</td></tr>\n"); | 52 | html("</td></tr>\n"); |
53 | start = idx + 1; | 53 | start = idx + 1; |
54 | } | 54 | } |
55 | idx++; | 55 | idx++; |
56 | } | 56 | } |
57 | htmlf(linefmt, ++lineno); | 57 | htmlf(linefmt, ++lineno); |
58 | html_txt(buf + start); | 58 | html_txt(buf + start); |
59 | html("</td></tr>\n"); | 59 | html("</td></tr>\n"); |
60 | html("</table>\n"); | 60 | html("</table>\n"); |
61 | } | 61 | } |
62 | 62 | ||
63 | 63 | ||
64 | static int ls_item(const unsigned char *sha1, const char *base, int baselen, | 64 | static int ls_item(const unsigned char *sha1, const char *base, int baselen, |
65 | const char *pathname, unsigned int mode, int stage, | 65 | const char *pathname, unsigned int mode, int stage, |
66 | void *cbdata) | 66 | void *cbdata) |
67 | { | 67 | { |
68 | char *name; | 68 | char *name; |
69 | char *fullpath; | 69 | char *fullpath; |
70 | enum object_type type; | 70 | enum object_type type; |
71 | unsigned long size = 0; | 71 | unsigned long size = 0; |
72 | 72 | ||
73 | name = xstrdup(pathname); | 73 | name = xstrdup(pathname); |
74 | fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", | 74 | fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", |
75 | ctx.qry.path ? "/" : "", name); | 75 | ctx.qry.path ? "/" : "", name); |
76 | 76 | ||
77 | if (!S_ISGITLINK(mode)) { | 77 | if (!S_ISGITLINK(mode)) { |
78 | type = sha1_object_info(sha1, &size); | 78 | type = sha1_object_info(sha1, &size); |
79 | if (type == OBJ_BAD) { | 79 | if (type == OBJ_BAD) { |
80 | htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", | 80 | htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", |
81 | name, | 81 | name, |
82 | sha1_to_hex(sha1)); | 82 | sha1_to_hex(sha1)); |
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | } | 85 | } |
86 | 86 | ||
87 | html("<tr><td class='ls-mode'>"); | 87 | html("<tr><td class='ls-mode'>"); |
88 | cgit_print_filemode(mode); | 88 | cgit_print_filemode(mode); |
89 | html("</td><td>"); | 89 | html("</td><td>"); |
90 | if (S_ISGITLINK(mode)) { | 90 | if (S_ISGITLINK(mode)) { |
91 | htmlf("<a class='ls-mod' href='"); | 91 | htmlf("<a class='ls-mod' href='"); |
92 | html_attr(fmt(ctx.repo->module_link, | 92 | html_attr(fmt(ctx.repo->module_link, |
93 | name, | 93 | name, |
94 | sha1_to_hex(sha1))); | 94 | sha1_to_hex(sha1))); |
95 | html("'>"); | 95 | html("'>"); |
96 | html_txt(name); | 96 | html_txt(name); |
97 | html("</a>"); | 97 | html("</a>"); |
98 | } else if (S_ISDIR(mode)) { | 98 | } else if (S_ISDIR(mode)) { |
99 | cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, | 99 | cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, |
100 | curr_rev, fullpath); | 100 | curr_rev, fullpath); |
101 | } else { | 101 | } else { |
102 | cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head, | 102 | cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head, |
103 | curr_rev, fullpath); | 103 | curr_rev, fullpath); |
104 | } | 104 | } |
105 | htmlf("</td><td class='ls-size'>%li</td>", size); | 105 | htmlf("</td><td class='ls-size'>%li</td>", size); |
106 | 106 | ||
107 | html("<td>"); | 107 | html("<td>"); |
108 | cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev, | 108 | cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev, |
109 | fullpath, 0, NULL, NULL); | 109 | fullpath, 0, NULL, NULL, ctx.qry.showmsg); |
110 | html("</td></tr>\n"); | 110 | html("</td></tr>\n"); |
111 | free(name); | 111 | free(name); |
112 | return 0; | 112 | return 0; |
113 | } | 113 | } |
114 | 114 | ||
115 | static void ls_head() | 115 | static void ls_head() |
116 | { | 116 | { |
117 | html("<table summary='tree listing' class='list'>\n"); | 117 | html("<table summary='tree listing' class='list'>\n"); |
118 | html("<tr class='nohover'>"); | 118 | html("<tr class='nohover'>"); |
119 | html("<th class='left'>Mode</th>"); | 119 | html("<th class='left'>Mode</th>"); |
120 | html("<th class='left'>Name</th>"); | 120 | html("<th class='left'>Name</th>"); |
121 | html("<th class='right'>Size</th>"); | 121 | html("<th class='right'>Size</th>"); |
122 | html("<th/>"); | 122 | html("<th/>"); |
123 | html("</tr>\n"); | 123 | html("</tr>\n"); |
124 | header = 1; | 124 | header = 1; |
125 | } | 125 | } |
126 | 126 | ||
127 | static void ls_tail() | 127 | static void ls_tail() |
128 | { | 128 | { |
129 | if (!header) | 129 | if (!header) |
130 | return; | 130 | return; |
131 | html("</table>\n"); | 131 | html("</table>\n"); |
132 | header = 0; | 132 | header = 0; |
133 | } | 133 | } |
134 | 134 | ||
135 | static void ls_tree(const unsigned char *sha1, char *path) | 135 | static void ls_tree(const unsigned char *sha1, char *path) |
136 | { | 136 | { |
137 | struct tree *tree; | 137 | struct tree *tree; |
138 | 138 | ||
139 | tree = parse_tree_indirect(sha1); | 139 | tree = parse_tree_indirect(sha1); |
140 | if (!tree) { | 140 | if (!tree) { |
141 | cgit_print_error(fmt("Not a tree object: %s", | 141 | cgit_print_error(fmt("Not a tree object: %s", |
142 | sha1_to_hex(sha1))); | 142 | sha1_to_hex(sha1))); |
143 | return; | 143 | return; |
144 | } | 144 | } |
145 | 145 | ||
146 | ls_head(); | 146 | ls_head(); |
147 | read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL); | 147 | read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL); |
148 | ls_tail(); | 148 | ls_tail(); |
149 | } | 149 | } |
150 | 150 | ||
151 | 151 | ||
152 | static int walk_tree(const unsigned char *sha1, const char *base, int baselen, | 152 | static int walk_tree(const unsigned char *sha1, const char *base, int baselen, |
153 | const char *pathname, unsigned mode, int stage, | 153 | const char *pathname, unsigned mode, int stage, |
154 | void *cbdata) | 154 | void *cbdata) |
155 | { | 155 | { |
156 | static int state; | 156 | static int state; |
157 | static char buffer[PATH_MAX]; | 157 | static char buffer[PATH_MAX]; |
158 | char *url; | 158 | char *url; |
159 | 159 | ||
160 | if (state == 0) { | 160 | if (state == 0) { |
161 | memcpy(buffer, base, baselen); | 161 | memcpy(buffer, base, baselen); |
162 | strcpy(buffer+baselen, pathname); | 162 | strcpy(buffer+baselen, pathname); |
163 | url = cgit_pageurl(ctx.qry.repo, "tree", | 163 | url = cgit_pageurl(ctx.qry.repo, "tree", |
164 | fmt("h=%s&path=%s", curr_rev, buffer)); | 164 | fmt("h=%s&path=%s", curr_rev, buffer)); |
165 | html("/"); | 165 | html("/"); |
166 | cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head, | 166 | cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head, |
167 | curr_rev, buffer); | 167 | curr_rev, buffer); |
168 | 168 | ||
169 | if (strcmp(match_path, buffer)) | 169 | if (strcmp(match_path, buffer)) |
170 | return READ_TREE_RECURSIVE; | 170 | return READ_TREE_RECURSIVE; |
171 | 171 | ||
172 | if (S_ISDIR(mode)) { | 172 | if (S_ISDIR(mode)) { |
173 | state = 1; | 173 | state = 1; |
174 | ls_head(); | 174 | ls_head(); |
175 | return READ_TREE_RECURSIVE; | 175 | return READ_TREE_RECURSIVE; |
176 | } else { | 176 | } else { |
177 | print_object(sha1, buffer); | 177 | print_object(sha1, buffer); |
178 | return 0; | 178 | return 0; |
179 | } | 179 | } |
180 | } | 180 | } |
181 | ls_item(sha1, base, baselen, pathname, mode, stage, NULL); | 181 | ls_item(sha1, base, baselen, pathname, mode, stage, NULL); |
182 | return 0; | 182 | return 0; |
183 | } | 183 | } |
184 | 184 | ||
185 | 185 | ||
186 | /* | 186 | /* |
187 | * Show a tree or a blob | 187 | * Show a tree or a blob |
188 | * rev: the commit pointing at the root tree object | 188 | * rev: the commit pointing at the root tree object |
189 | * path: path to tree or blob | 189 | * path: path to tree or blob |
190 | */ | 190 | */ |
191 | void cgit_print_tree(const char *rev, char *path) | 191 | void cgit_print_tree(const char *rev, char *path) |
192 | { | 192 | { |
193 | unsigned char sha1[20]; | 193 | unsigned char sha1[20]; |
194 | struct commit *commit; | 194 | struct commit *commit; |
195 | const char *paths[] = {path, NULL}; | 195 | const char *paths[] = {path, NULL}; |
196 | 196 | ||
197 | if (!rev) | 197 | if (!rev) |
198 | rev = ctx.qry.head; | 198 | rev = ctx.qry.head; |
199 | 199 | ||
200 | curr_rev = xstrdup(rev); | 200 | curr_rev = xstrdup(rev); |
201 | if (get_sha1(rev, sha1)) { | 201 | if (get_sha1(rev, sha1)) { |
202 | cgit_print_error(fmt("Invalid revision name: %s", rev)); | 202 | cgit_print_error(fmt("Invalid revision name: %s", rev)); |
203 | return; | 203 | return; |
204 | } | 204 | } |
205 | commit = lookup_commit_reference(sha1); | 205 | commit = lookup_commit_reference(sha1); |