summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.h3
-rw-r--r--shared.c4
-rw-r--r--ui-log.c2
3 files changed, 5 insertions, 4 deletions
diff --git a/cgit.h b/cgit.h
index a9896cf..f5f68ac 100644
--- a/cgit.h
+++ b/cgit.h
@@ -201,117 +201,118 @@ struct cgit_config {
201 int max_msg_len; 201 int max_msg_len;
202 int max_repodesc_len; 202 int max_repodesc_len;
203 int max_blob_size; 203 int max_blob_size;
204 int max_stats; 204 int max_stats;
205 int nocache; 205 int nocache;
206 int noplainemail; 206 int noplainemail;
207 int noheader; 207 int noheader;
208 int renamelimit; 208 int renamelimit;
209 int remove_suffix; 209 int remove_suffix;
210 int section_from_path; 210 int section_from_path;
211 int snapshots; 211 int snapshots;
212 int summary_branches; 212 int summary_branches;
213 int summary_log; 213 int summary_log;
214 int summary_tags; 214 int summary_tags;
215 int ssdiff; 215 int ssdiff;
216 struct string_list mimetypes; 216 struct string_list mimetypes;
217 struct cgit_filter *about_filter; 217 struct cgit_filter *about_filter;
218 struct cgit_filter *commit_filter; 218 struct cgit_filter *commit_filter;
219 struct cgit_filter *source_filter; 219 struct cgit_filter *source_filter;
220}; 220};
221 221
222struct cgit_page { 222struct cgit_page {
223 time_t modified; 223 time_t modified;
224 time_t expires; 224 time_t expires;
225 size_t size; 225 size_t size;
226 char *mimetype; 226 char *mimetype;
227 char *charset; 227 char *charset;
228 char *filename; 228 char *filename;
229 char *etag; 229 char *etag;
230 char *title; 230 char *title;
231 int status; 231 int status;
232 char *statusmsg; 232 char *statusmsg;
233}; 233};
234 234
235struct cgit_environment { 235struct cgit_environment {
236 char *cgit_config; 236 char *cgit_config;
237 char *http_host; 237 char *http_host;
238 char *https; 238 char *https;
239 char *no_http; 239 char *no_http;
240 char *path_info; 240 char *path_info;
241 char *query_string; 241 char *query_string;
242 char *request_method; 242 char *request_method;
243 char *script_name; 243 char *script_name;
244 char *server_name; 244 char *server_name;
245 char *server_port; 245 char *server_port;
246}; 246};
247 247
248struct cgit_context { 248struct cgit_context {
249 struct cgit_environment env; 249 struct cgit_environment env;
250 struct cgit_query qry; 250 struct cgit_query qry;
251 struct cgit_config cfg; 251 struct cgit_config cfg;
252 struct cgit_repo *repo; 252 struct cgit_repo *repo;
253 struct cgit_page page; 253 struct cgit_page page;
254}; 254};
255 255
256struct cgit_snapshot_format { 256struct cgit_snapshot_format {
257 const char *suffix; 257 const char *suffix;
258 const char *mimetype; 258 const char *mimetype;
259 write_archive_fn_t write_func; 259 write_archive_fn_t write_func;
260 int bit; 260 int bit;
261}; 261};
262 262
263extern const char *cgit_version; 263extern const char *cgit_version;
264 264
265extern struct cgit_repolist cgit_repolist; 265extern struct cgit_repolist cgit_repolist;
266extern struct cgit_context ctx; 266extern struct cgit_context ctx;
267extern const struct cgit_snapshot_format cgit_snapshot_formats[]; 267extern const struct cgit_snapshot_format cgit_snapshot_formats[];
268 268
269extern struct cgit_repo *cgit_add_repo(const char *url); 269extern struct cgit_repo *cgit_add_repo(const char *url);
270extern struct cgit_repo *cgit_get_repoinfo(const char *url); 270extern struct cgit_repo *cgit_get_repoinfo(const char *url);
271extern void cgit_repo_config_cb(const char *name, const char *value); 271extern void cgit_repo_config_cb(const char *name, const char *value);
272 272
273extern int chk_zero(int result, char *msg); 273extern int chk_zero(int result, char *msg);
274extern int chk_positive(int result, char *msg); 274extern int chk_positive(int result, char *msg);
275extern int chk_non_negative(int result, char *msg); 275extern int chk_non_negative(int result, char *msg);
276 276
277extern char *trim_end(const char *str, char c); 277extern char *trim_end(const char *str, char c);
278extern char *strlpart(char *txt, int maxlen); 278extern char *strlpart(char *txt, int maxlen);
279extern char *strrpart(char *txt, int maxlen); 279extern char *strrpart(char *txt, int maxlen);
280 280
281extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); 281extern void cgit_add_ref(struct reflist *list, struct refinfo *ref);
282extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, 282extern int cgit_refs_cb(const char *refname, const unsigned char *sha1,
283 int flags, void *cb_data); 283 int flags, void *cb_data);
284 284
285extern void *cgit_free_commitinfo(struct commitinfo *info); 285extern void *cgit_free_commitinfo(struct commitinfo *info);
286 286
287extern int cgit_diff_files(const unsigned char *old_sha1, 287extern int cgit_diff_files(const unsigned char *old_sha1,
288 const unsigned char *new_sha1, 288 const unsigned char *new_sha1,
289 unsigned long *old_size, unsigned long *new_size, 289 unsigned long *old_size, unsigned long *new_size,
290 int *binary, int context, int ignorews, 290 int *binary, int context, int ignorews,
291 linediff_fn fn); 291 linediff_fn fn);
292 292
293extern void cgit_diff_tree(const unsigned char *old_sha1, 293extern void cgit_diff_tree(const unsigned char *old_sha1,
294 const unsigned char *new_sha1, 294 const unsigned char *new_sha1,
295 filepair_fn fn, const char *prefix, int ignorews); 295 filepair_fn fn, const char *prefix, int ignorews);
296 296
297extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 297extern void cgit_diff_commit(struct commit *commit, filepair_fn fn,
298 const char *prefix);
298 299
299__attribute__((format (printf,1,2))) 300__attribute__((format (printf,1,2)))
300extern char *fmt(const char *format,...); 301extern char *fmt(const char *format,...);
301 302
302extern struct commitinfo *cgit_parse_commit(struct commit *commit); 303extern struct commitinfo *cgit_parse_commit(struct commit *commit);
303extern struct taginfo *cgit_parse_tag(struct tag *tag); 304extern struct taginfo *cgit_parse_tag(struct tag *tag);
304extern void cgit_parse_url(const char *url); 305extern void cgit_parse_url(const char *url);
305 306
306extern const char *cgit_repobasename(const char *reponame); 307extern const char *cgit_repobasename(const char *reponame);
307 308
308extern int cgit_parse_snapshots_mask(const char *str); 309extern int cgit_parse_snapshots_mask(const char *str);
309 310
310extern int cgit_open_filter(struct cgit_filter *filter); 311extern int cgit_open_filter(struct cgit_filter *filter);
311extern int cgit_close_filter(struct cgit_filter *filter); 312extern int cgit_close_filter(struct cgit_filter *filter);
312 313
313extern int readfile(const char *path, char **buf, size_t *size); 314extern int readfile(const char *path, char **buf, size_t *size);
314 315
315extern char *expand_macros(const char *txt); 316extern char *expand_macros(const char *txt);
316 317
317#endif /* CGIT_H */ 318#endif /* CGIT_H */
diff --git a/shared.c b/shared.c
index 72ac140..765cd27 100644
--- a/shared.c
+++ b/shared.c
@@ -245,199 +245,199 @@ int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)
245 ((linediff_fn)priv)(mb[i].ptr, mb[i].size); 245 ((linediff_fn)priv)(mb[i].ptr, mb[i].size);
246 continue; 246 continue;
247 } 247 }
248 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 248 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
249 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 249 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
250 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size); 250 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size);
251 free(diffbuf); 251 free(diffbuf);
252 diffbuf = NULL; 252 diffbuf = NULL;
253 buflen = 0; 253 buflen = 0;
254 } 254 }
255 if (diffbuf) { 255 if (diffbuf) {
256 ((linediff_fn)priv)(diffbuf, buflen); 256 ((linediff_fn)priv)(diffbuf, buflen);
257 free(diffbuf); 257 free(diffbuf);
258 diffbuf = NULL; 258 diffbuf = NULL;
259 buflen = 0; 259 buflen = 0;
260 } 260 }
261 return 0; 261 return 0;
262} 262}
263 263
264int cgit_diff_files(const unsigned char *old_sha1, 264int cgit_diff_files(const unsigned char *old_sha1,
265 const unsigned char *new_sha1, unsigned long *old_size, 265 const unsigned char *new_sha1, unsigned long *old_size,
266 unsigned long *new_size, int *binary, int context, 266 unsigned long *new_size, int *binary, int context,
267 int ignorews, linediff_fn fn) 267 int ignorews, linediff_fn fn)
268{ 268{
269 mmfile_t file1, file2; 269 mmfile_t file1, file2;
270 xpparam_t diff_params; 270 xpparam_t diff_params;
271 xdemitconf_t emit_params; 271 xdemitconf_t emit_params;
272 xdemitcb_t emit_cb; 272 xdemitcb_t emit_cb;
273 273
274 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1)) 274 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1))
275 return 1; 275 return 1;
276 276
277 *old_size = file1.size; 277 *old_size = file1.size;
278 *new_size = file2.size; 278 *new_size = file2.size;
279 279
280 if ((file1.ptr && buffer_is_binary(file1.ptr, file1.size)) || 280 if ((file1.ptr && buffer_is_binary(file1.ptr, file1.size)) ||
281 (file2.ptr && buffer_is_binary(file2.ptr, file2.size))) { 281 (file2.ptr && buffer_is_binary(file2.ptr, file2.size))) {
282 *binary = 1; 282 *binary = 1;
283 if (file1.size) 283 if (file1.size)
284 free(file1.ptr); 284 free(file1.ptr);
285 if (file2.size) 285 if (file2.size)
286 free(file2.ptr); 286 free(file2.ptr);
287 return 0; 287 return 0;
288 } 288 }
289 289
290 memset(&diff_params, 0, sizeof(diff_params)); 290 memset(&diff_params, 0, sizeof(diff_params));
291 memset(&emit_params, 0, sizeof(emit_params)); 291 memset(&emit_params, 0, sizeof(emit_params));
292 memset(&emit_cb, 0, sizeof(emit_cb)); 292 memset(&emit_cb, 0, sizeof(emit_cb));
293 diff_params.flags = XDF_NEED_MINIMAL; 293 diff_params.flags = XDF_NEED_MINIMAL;
294 if (ignorews) 294 if (ignorews)
295 diff_params.flags |= XDF_IGNORE_WHITESPACE; 295 diff_params.flags |= XDF_IGNORE_WHITESPACE;
296 emit_params.ctxlen = context > 0 ? context : 3; 296 emit_params.ctxlen = context > 0 ? context : 3;
297 emit_params.flags = XDL_EMIT_FUNCNAMES; 297 emit_params.flags = XDL_EMIT_FUNCNAMES;
298 emit_cb.outf = filediff_cb; 298 emit_cb.outf = filediff_cb;
299 emit_cb.priv = fn; 299 emit_cb.priv = fn;
300 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); 300 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb);
301 if (file1.size) 301 if (file1.size)
302 free(file1.ptr); 302 free(file1.ptr);
303 if (file2.size) 303 if (file2.size)
304 free(file2.ptr); 304 free(file2.ptr);
305 return 0; 305 return 0;
306} 306}
307 307
308void cgit_diff_tree(const unsigned char *old_sha1, 308void cgit_diff_tree(const unsigned char *old_sha1,
309 const unsigned char *new_sha1, 309 const unsigned char *new_sha1,
310 filepair_fn fn, const char *prefix, int ignorews) 310 filepair_fn fn, const char *prefix, int ignorews)
311{ 311{
312 struct diff_options opt; 312 struct diff_options opt;
313 int ret; 313 int ret;
314 int prefixlen; 314 int prefixlen;
315 315
316 diff_setup(&opt); 316 diff_setup(&opt);
317 opt.output_format = DIFF_FORMAT_CALLBACK; 317 opt.output_format = DIFF_FORMAT_CALLBACK;
318 opt.detect_rename = 1; 318 opt.detect_rename = 1;
319 opt.rename_limit = ctx.cfg.renamelimit; 319 opt.rename_limit = ctx.cfg.renamelimit;
320 DIFF_OPT_SET(&opt, RECURSIVE); 320 DIFF_OPT_SET(&opt, RECURSIVE);
321 if (ignorews) 321 if (ignorews)
322 DIFF_XDL_SET(&opt, IGNORE_WHITESPACE); 322 DIFF_XDL_SET(&opt, IGNORE_WHITESPACE);
323 opt.format_callback = cgit_diff_tree_cb; 323 opt.format_callback = cgit_diff_tree_cb;
324 opt.format_callback_data = fn; 324 opt.format_callback_data = fn;
325 if (prefix) { 325 if (prefix) {
326 opt.nr_paths = 1; 326 opt.nr_paths = 1;
327 opt.paths = &prefix; 327 opt.paths = &prefix;
328 prefixlen = strlen(prefix); 328 prefixlen = strlen(prefix);
329 opt.pathlens = &prefixlen; 329 opt.pathlens = &prefixlen;
330 } 330 }
331 diff_setup_done(&opt); 331 diff_setup_done(&opt);
332 332
333 if (old_sha1 && !is_null_sha1(old_sha1)) 333 if (old_sha1 && !is_null_sha1(old_sha1))
334 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt); 334 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt);
335 else 335 else
336 ret = diff_root_tree_sha1(new_sha1, "", &opt); 336 ret = diff_root_tree_sha1(new_sha1, "", &opt);
337 diffcore_std(&opt); 337 diffcore_std(&opt);
338 diff_flush(&opt); 338 diff_flush(&opt);
339} 339}
340 340
341void cgit_diff_commit(struct commit *commit, filepair_fn fn) 341void cgit_diff_commit(struct commit *commit, filepair_fn fn, const char *prefix)
342{ 342{
343 unsigned char *old_sha1 = NULL; 343 unsigned char *old_sha1 = NULL;
344 344
345 if (commit->parents) 345 if (commit->parents)
346 old_sha1 = commit->parents->item->object.sha1; 346 old_sha1 = commit->parents->item->object.sha1;
347 cgit_diff_tree(old_sha1, commit->object.sha1, fn, NULL, 347 cgit_diff_tree(old_sha1, commit->object.sha1, fn, prefix,
348 ctx.qry.ignorews); 348 ctx.qry.ignorews);
349} 349}
350 350
351int cgit_parse_snapshots_mask(const char *str) 351int cgit_parse_snapshots_mask(const char *str)
352{ 352{
353 const struct cgit_snapshot_format *f; 353 const struct cgit_snapshot_format *f;
354 static const char *delim = " \t,:/|;"; 354 static const char *delim = " \t,:/|;";
355 int tl, sl, rv = 0; 355 int tl, sl, rv = 0;
356 356
357 /* favor legacy setting */ 357 /* favor legacy setting */
358 if(atoi(str)) 358 if(atoi(str))
359 return 1; 359 return 1;
360 for(;;) { 360 for(;;) {
361 str += strspn(str,delim); 361 str += strspn(str,delim);
362 tl = strcspn(str,delim); 362 tl = strcspn(str,delim);
363 if (!tl) 363 if (!tl)
364 break; 364 break;
365 for (f = cgit_snapshot_formats; f->suffix; f++) { 365 for (f = cgit_snapshot_formats; f->suffix; f++) {
366 sl = strlen(f->suffix); 366 sl = strlen(f->suffix);
367 if((tl == sl && !strncmp(f->suffix, str, tl)) || 367 if((tl == sl && !strncmp(f->suffix, str, tl)) ||
368 (tl == sl-1 && !strncmp(f->suffix+1, str, tl-1))) { 368 (tl == sl-1 && !strncmp(f->suffix+1, str, tl-1))) {
369 rv |= f->bit; 369 rv |= f->bit;
370 break; 370 break;
371 } 371 }
372 } 372 }
373 str += tl; 373 str += tl;
374 } 374 }
375 return rv; 375 return rv;
376} 376}
377 377
378int cgit_open_filter(struct cgit_filter *filter) 378int cgit_open_filter(struct cgit_filter *filter)
379{ 379{
380 380
381 filter->old_stdout = chk_positive(dup(STDOUT_FILENO), 381 filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
382 "Unable to duplicate STDOUT"); 382 "Unable to duplicate STDOUT");
383 chk_zero(pipe(filter->pipe_fh), "Unable to create pipe to subprocess"); 383 chk_zero(pipe(filter->pipe_fh), "Unable to create pipe to subprocess");
384 filter->pid = chk_non_negative(fork(), "Unable to create subprocess"); 384 filter->pid = chk_non_negative(fork(), "Unable to create subprocess");
385 if (filter->pid == 0) { 385 if (filter->pid == 0) {
386 close(filter->pipe_fh[1]); 386 close(filter->pipe_fh[1]);
387 chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO), 387 chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO),
388 "Unable to use pipe as STDIN"); 388 "Unable to use pipe as STDIN");
389 execvp(filter->cmd, filter->argv); 389 execvp(filter->cmd, filter->argv);
390 die("Unable to exec subprocess %s: %s (%d)", filter->cmd, 390 die("Unable to exec subprocess %s: %s (%d)", filter->cmd,
391 strerror(errno), errno); 391 strerror(errno), errno);
392 } 392 }
393 close(filter->pipe_fh[0]); 393 close(filter->pipe_fh[0]);
394 chk_non_negative(dup2(filter->pipe_fh[1], STDOUT_FILENO), 394 chk_non_negative(dup2(filter->pipe_fh[1], STDOUT_FILENO),
395 "Unable to use pipe as STDOUT"); 395 "Unable to use pipe as STDOUT");
396 close(filter->pipe_fh[1]); 396 close(filter->pipe_fh[1]);
397 return 0; 397 return 0;
398} 398}
399 399
400int cgit_close_filter(struct cgit_filter *filter) 400int cgit_close_filter(struct cgit_filter *filter)
401{ 401{
402 chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO), 402 chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO),
403 "Unable to restore STDOUT"); 403 "Unable to restore STDOUT");
404 close(filter->old_stdout); 404 close(filter->old_stdout);
405 if (filter->pid < 0) 405 if (filter->pid < 0)
406 return 0; 406 return 0;
407 waitpid(filter->pid, &filter->exitstatus, 0); 407 waitpid(filter->pid, &filter->exitstatus, 0);
408 if (WIFEXITED(filter->exitstatus) && !WEXITSTATUS(filter->exitstatus)) 408 if (WIFEXITED(filter->exitstatus) && !WEXITSTATUS(filter->exitstatus))
409 return 0; 409 return 0;
410 die("Subprocess %s exited abnormally", filter->cmd); 410 die("Subprocess %s exited abnormally", filter->cmd);
411} 411}
412 412
413/* Read the content of the specified file into a newly allocated buffer, 413/* Read the content of the specified file into a newly allocated buffer,
414 * zeroterminate the buffer and return 0 on success, errno otherwise. 414 * zeroterminate the buffer and return 0 on success, errno otherwise.
415 */ 415 */
416int readfile(const char *path, char **buf, size_t *size) 416int readfile(const char *path, char **buf, size_t *size)
417{ 417{
418 int fd, e; 418 int fd, e;
419 struct stat st; 419 struct stat st;
420 420
421 fd = open(path, O_RDONLY); 421 fd = open(path, O_RDONLY);
422 if (fd == -1) 422 if (fd == -1)
423 return errno; 423 return errno;
424 if (fstat(fd, &st)) { 424 if (fstat(fd, &st)) {
425 e = errno; 425 e = errno;
426 close(fd); 426 close(fd);
427 return e; 427 return e;
428 } 428 }
429 if (!S_ISREG(st.st_mode)) { 429 if (!S_ISREG(st.st_mode)) {
430 close(fd); 430 close(fd);
431 return EISDIR; 431 return EISDIR;
432 } 432 }
433 *buf = xmalloc(st.st_size + 1); 433 *buf = xmalloc(st.st_size + 1);
434 *size = read_in_full(fd, *buf, st.st_size); 434 *size = read_in_full(fd, *buf, st.st_size);
435 e = errno; 435 e = errno;
436 (*buf)[*size] = '\0'; 436 (*buf)[*size] = '\0';
437 close(fd); 437 close(fd);
438 return (*size == st.st_size ? 0 : e); 438 return (*size == st.st_size ? 0 : e);
439} 439}
440 440
441int is_token_char(char c) 441int is_token_char(char c)
442{ 442{
443 return isalnum(c) || c == '_'; 443 return isalnum(c) || c == '_';
diff --git a/ui-log.c b/ui-log.c
index 41b5225..bc0c02c 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -8,193 +8,193 @@
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
13int files, add_lines, rem_lines; 13int files, add_lines, rem_lines;
14 14
15void count_lines(char *line, int size) 15void 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
27void inspect_files(struct diff_filepair *pair) 27void inspect_files(struct diff_filepair *pair)
28{ 28{
29 unsigned long old_size = 0; 29 unsigned long old_size = 0;
30 unsigned long new_size = 0; 30 unsigned long new_size = 0;
31 int binary = 0; 31 int binary = 0;
32 32
33 files++; 33 files++;
34 if (ctx.repo->enable_log_linecount) 34 if (ctx.repo->enable_log_linecount)
35 cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, 35 cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size,
36 &new_size, &binary, 0, ctx.qry.ignorews, 36 &new_size, &binary, 0, ctx.qry.ignorews,
37 count_lines); 37 count_lines);
38} 38}
39 39
40void show_commit_decorations(struct commit *commit) 40void show_commit_decorations(struct commit *commit)
41{ 41{
42 struct name_decoration *deco; 42 struct name_decoration *deco;
43 static char buf[1024]; 43 static char buf[1024];
44 44
45 buf[sizeof(buf) - 1] = 0; 45 buf[sizeof(buf) - 1] = 0;
46 deco = lookup_decoration(&name_decoration, &commit->object); 46 deco = lookup_decoration(&name_decoration, &commit->object);
47 while (deco) { 47 while (deco) {
48 if (!prefixcmp(deco->name, "refs/heads/")) { 48 if (!prefixcmp(deco->name, "refs/heads/")) {
49 strncpy(buf, deco->name + 11, sizeof(buf) - 1); 49 strncpy(buf, deco->name + 11, sizeof(buf) - 1);
50 cgit_log_link(buf, NULL, "branch-deco", buf, NULL, 50 cgit_log_link(buf, NULL, "branch-deco", buf, NULL,
51 ctx.qry.vpath, 0, NULL, NULL, 51 ctx.qry.vpath, 0, NULL, NULL,
52 ctx.qry.showmsg); 52 ctx.qry.showmsg);
53 } 53 }
54 else if (!prefixcmp(deco->name, "tag: refs/tags/")) { 54 else if (!prefixcmp(deco->name, "tag: refs/tags/")) {
55 strncpy(buf, deco->name + 15, sizeof(buf) - 1); 55 strncpy(buf, deco->name + 15, sizeof(buf) - 1);
56 cgit_tag_link(buf, NULL, "tag-deco", ctx.qry.head, buf); 56 cgit_tag_link(buf, NULL, "tag-deco", ctx.qry.head, buf);
57 } 57 }
58 else if (!prefixcmp(deco->name, "refs/tags/")) { 58 else if (!prefixcmp(deco->name, "refs/tags/")) {
59 strncpy(buf, deco->name + 10, sizeof(buf) - 1); 59 strncpy(buf, deco->name + 10, sizeof(buf) - 1);
60 cgit_tag_link(buf, NULL, "tag-deco", ctx.qry.head, buf); 60 cgit_tag_link(buf, NULL, "tag-deco", ctx.qry.head, buf);
61 } 61 }
62 else if (!prefixcmp(deco->name, "refs/remotes/")) { 62 else if (!prefixcmp(deco->name, "refs/remotes/")) {
63 strncpy(buf, deco->name + 13, sizeof(buf) - 1); 63 strncpy(buf, deco->name + 13, sizeof(buf) - 1);
64 cgit_log_link(buf, NULL, "remote-deco", NULL, 64 cgit_log_link(buf, NULL, "remote-deco", NULL,
65 sha1_to_hex(commit->object.sha1), 65 sha1_to_hex(commit->object.sha1),
66 ctx.qry.vpath, 0, NULL, NULL, 66 ctx.qry.vpath, 0, NULL, NULL,
67 ctx.qry.showmsg); 67 ctx.qry.showmsg);
68 } 68 }
69 else { 69 else {
70 strncpy(buf, deco->name, sizeof(buf) - 1); 70 strncpy(buf, deco->name, sizeof(buf) - 1);
71 cgit_commit_link(buf, NULL, "deco", ctx.qry.head, 71 cgit_commit_link(buf, NULL, "deco", ctx.qry.head,
72 sha1_to_hex(commit->object.sha1), 72 sha1_to_hex(commit->object.sha1),
73 ctx.qry.vpath, 0); 73 ctx.qry.vpath, 0);
74 } 74 }
75 deco = deco->next; 75 deco = deco->next;
76 } 76 }
77} 77}
78 78
79void print_commit(struct commit *commit) 79void print_commit(struct commit *commit)
80{ 80{
81 struct commitinfo *info; 81 struct commitinfo *info;
82 char *tmp; 82 char *tmp;
83 int cols = 2; 83 int cols = 2;
84 84
85 info = cgit_parse_commit(commit); 85 info = cgit_parse_commit(commit);
86 htmlf("<tr%s><td>", 86 htmlf("<tr%s><td>",
87 ctx.qry.showmsg ? " class='logheader'" : ""); 87 ctx.qry.showmsg ? " class='logheader'" : "");
88 tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1)); 88 tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1));
89 tmp = cgit_fileurl(ctx.repo->url, "commit", ctx.qry.vpath, tmp); 89 tmp = cgit_fileurl(ctx.repo->url, "commit", ctx.qry.vpath, tmp);
90 html_link_open(tmp, NULL, NULL); 90 html_link_open(tmp, NULL, NULL);
91 cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); 91 cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
92 html_link_close(); 92 html_link_close();
93 htmlf("</td><td%s>", 93 htmlf("</td><td%s>",
94 ctx.qry.showmsg ? " class='logsubject'" : ""); 94 ctx.qry.showmsg ? " class='logsubject'" : "");
95 cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, 95 cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,
96 sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0); 96 sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);
97 show_commit_decorations(commit); 97 show_commit_decorations(commit);
98 html("</td><td>"); 98 html("</td><td>");
99 html_txt(info->author); 99 html_txt(info->author);
100 if (ctx.repo->enable_log_filecount) { 100 if (ctx.repo->enable_log_filecount) {
101 files = 0; 101 files = 0;
102 add_lines = 0; 102 add_lines = 0;
103 rem_lines = 0; 103 rem_lines = 0;
104 cgit_diff_commit(commit, inspect_files); 104 cgit_diff_commit(commit, inspect_files, ctx.qry.vpath);
105 html("</td><td>"); 105 html("</td><td>");
106 htmlf("%d", files); 106 htmlf("%d", files);
107 if (ctx.repo->enable_log_linecount) { 107 if (ctx.repo->enable_log_linecount) {
108 html("</td><td>"); 108 html("</td><td>");
109 htmlf("-%d/+%d", rem_lines, add_lines); 109 htmlf("-%d/+%d", rem_lines, add_lines);
110 } 110 }
111 } 111 }
112 html("</td></tr>\n"); 112 html("</td></tr>\n");
113 if (ctx.qry.showmsg) { 113 if (ctx.qry.showmsg) {
114 struct strbuf notes = STRBUF_INIT; 114 struct strbuf notes = STRBUF_INIT;
115 format_note(NULL, commit->object.sha1, &notes, PAGE_ENCODING, 0); 115 format_note(NULL, commit->object.sha1, &notes, PAGE_ENCODING, 0);
116 116
117 if (ctx.repo->enable_log_filecount) { 117 if (ctx.repo->enable_log_filecount) {
118 cols++; 118 cols++;
119 if (ctx.repo->enable_log_linecount) 119 if (ctx.repo->enable_log_linecount)
120 cols++; 120 cols++;
121 } 121 }
122 htmlf("<tr class='nohover'><td/><td colspan='%d' class='logmsg'>", 122 htmlf("<tr class='nohover'><td/><td colspan='%d' class='logmsg'>",
123 cols); 123 cols);
124 html_txt(info->msg); 124 html_txt(info->msg);
125 html("</td></tr>\n"); 125 html("</td></tr>\n");
126 if (notes.len != 0) { 126 if (notes.len != 0) {
127 html("<tr class='nohover'>"); 127 html("<tr class='nohover'>");
128 html("<td class='lognotes-label'>Notes:</td>"); 128 html("<td class='lognotes-label'>Notes:</td>");
129 htmlf("<td colspan='%d' class='lognotes'>", 129 htmlf("<td colspan='%d' class='lognotes'>",
130 cols); 130 cols);
131 html_txt(notes.buf); 131 html_txt(notes.buf);
132 html("</td></tr>\n"); 132 html("</td></tr>\n");
133 } 133 }
134 strbuf_release(&notes); 134 strbuf_release(&notes);
135 } 135 }
136 cgit_free_commitinfo(info); 136 cgit_free_commitinfo(info);
137} 137}
138 138
139static const char *disambiguate_ref(const char *ref) 139static const char *disambiguate_ref(const char *ref)
140{ 140{
141 unsigned char sha1[20]; 141 unsigned char sha1[20];
142 const char *longref; 142 const char *longref;
143 143
144 longref = fmt("refs/heads/%s", ref); 144 longref = fmt("refs/heads/%s", ref);
145 if (get_sha1(longref, sha1) == 0) 145 if (get_sha1(longref, sha1) == 0)
146 return longref; 146 return longref;
147 147
148 return ref; 148 return ref;
149} 149}
150 150
151void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern, 151void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern,
152 char *path, int pager) 152 char *path, int pager)
153{ 153{
154 struct rev_info rev; 154 struct rev_info rev;
155 struct commit *commit; 155 struct commit *commit;
156 const char *argv[] = {NULL, NULL, NULL, NULL, NULL}; 156 const char *argv[] = {NULL, NULL, NULL, NULL, NULL};
157 int argc = 2; 157 int argc = 2;
158 int i, columns = 3; 158 int i, columns = 3;
159 159
160 if (!tip) 160 if (!tip)
161 tip = ctx.qry.head; 161 tip = ctx.qry.head;
162 162
163 argv[1] = disambiguate_ref(tip); 163 argv[1] = disambiguate_ref(tip);
164 164
165 if (grep && pattern) { 165 if (grep && pattern) {
166 if (!strcmp(grep, "grep") || !strcmp(grep, "author") || 166 if (!strcmp(grep, "grep") || !strcmp(grep, "author") ||
167 !strcmp(grep, "committer")) 167 !strcmp(grep, "committer"))
168 argv[argc++] = fmt("--%s=%s", grep, pattern); 168 argv[argc++] = fmt("--%s=%s", grep, pattern);
169 if (!strcmp(grep, "range")) 169 if (!strcmp(grep, "range"))
170 argv[1] = pattern; 170 argv[1] = pattern;
171 } 171 }
172 172
173 if (path) { 173 if (path) {
174 argv[argc++] = "--"; 174 argv[argc++] = "--";
175 argv[argc++] = path; 175 argv[argc++] = path;
176 } 176 }
177 init_revisions(&rev, NULL); 177 init_revisions(&rev, NULL);
178 rev.abbrev = DEFAULT_ABBREV; 178 rev.abbrev = DEFAULT_ABBREV;
179 rev.commit_format = CMIT_FMT_DEFAULT; 179 rev.commit_format = CMIT_FMT_DEFAULT;
180 rev.verbose_header = 1; 180 rev.verbose_header = 1;
181 rev.show_root_diff = 0; 181 rev.show_root_diff = 0;
182 setup_revisions(argc, argv, &rev, NULL); 182 setup_revisions(argc, argv, &rev, NULL);
183 load_ref_decorations(DECORATE_FULL_REFS); 183 load_ref_decorations(DECORATE_FULL_REFS);
184 rev.show_decorations = 1; 184 rev.show_decorations = 1;
185 rev.grep_filter.regflags |= REG_ICASE; 185 rev.grep_filter.regflags |= REG_ICASE;
186 compile_grep_patterns(&rev.grep_filter); 186 compile_grep_patterns(&rev.grep_filter);
187 prepare_revision_walk(&rev); 187 prepare_revision_walk(&rev);
188 188
189 if (pager) 189 if (pager)
190 html("<table class='list nowrap'>"); 190 html("<table class='list nowrap'>");
191 191
192 html("<tr class='nohover'><th class='left'>Age</th>" 192 html("<tr class='nohover'><th class='left'>Age</th>"
193 "<th class='left'>Commit message"); 193 "<th class='left'>Commit message");
194 if (pager) { 194 if (pager) {
195 html(" ("); 195 html(" (");
196 cgit_log_link(ctx.qry.showmsg ? "Collapse" : "Expand", NULL, 196 cgit_log_link(ctx.qry.showmsg ? "Collapse" : "Expand", NULL,
197 NULL, ctx.qry.head, ctx.qry.sha1, 197 NULL, ctx.qry.head, ctx.qry.sha1,
198 ctx.qry.vpath, ctx.qry.ofs, ctx.qry.grep, 198 ctx.qry.vpath, ctx.qry.ofs, ctx.qry.grep,
199 ctx.qry.search, ctx.qry.showmsg ? 0 : 1); 199 ctx.qry.search, ctx.qry.showmsg ? 0 : 1);
200 html(")"); 200 html(")");