summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2007-05-18 11:55:52 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2007-05-18 11:55:52 (UTC)
commite189344a7dfe6fa1b07434d5170e6441dcbaf788 (patch) (unidiff)
treef1500b97f95a710dba27469510114388be435d01
parentc1ad6cb77889880ad0189a689840fbfa6e5cbc80 (diff)
downloadcgit-e189344a7dfe6fa1b07434d5170e6441dcbaf788.zip
cgit-e189344a7dfe6fa1b07434d5170e6441dcbaf788.tar.gz
cgit-e189344a7dfe6fa1b07434d5170e6441dcbaf788.tar.bz2
Add knobs to enable/disable files/lines changed in log view
These columns can cause lots of IO on the server, so add settings to explicitly enable them. Also, add per repo settings to optionally disable the columns if sitewide enabled. While at it, do not allow repo.snapshot to enable snapshots if the global setting is disabled. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.h4
-rw-r--r--cgitrc10
-rw-r--r--shared.c14
-rw-r--r--ui-log.c33
4 files changed, 48 insertions, 13 deletions
diff --git a/cgit.h b/cgit.h
index 290401f..ed100a7 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,186 +1,190 @@
1#ifndef CGIT_H 1#ifndef CGIT_H
2#define CGIT_H 2#define CGIT_H
3 3
4 4
5#include <git-compat-util.h> 5#include <git-compat-util.h>
6#include <cache.h> 6#include <cache.h>
7#include <grep.h> 7#include <grep.h>
8#include <object.h> 8#include <object.h>
9#include <tree.h> 9#include <tree.h>
10#include <commit.h> 10#include <commit.h>
11#include <tag.h> 11#include <tag.h>
12#include <diff.h> 12#include <diff.h>
13#include <diffcore.h> 13#include <diffcore.h>
14#include <refs.h> 14#include <refs.h>
15#include <revision.h> 15#include <revision.h>
16#include <log-tree.h> 16#include <log-tree.h>
17#include <archive.h> 17#include <archive.h>
18#include <xdiff/xdiff.h> 18#include <xdiff/xdiff.h>
19 19
20 20
21typedef void (*configfn)(const char *name, const char *value); 21typedef void (*configfn)(const char *name, const char *value);
22typedef void (*filepair_fn)(struct diff_filepair *pair); 22typedef void (*filepair_fn)(struct diff_filepair *pair);
23typedef void (*linediff_fn)(char *line, int len); 23typedef void (*linediff_fn)(char *line, int len);
24 24
25struct cacheitem { 25struct cacheitem {
26 char *name; 26 char *name;
27 struct stat st; 27 struct stat st;
28 int ttl; 28 int ttl;
29 int fd; 29 int fd;
30}; 30};
31 31
32struct repoinfo { 32struct repoinfo {
33 char *url; 33 char *url;
34 char *name; 34 char *name;
35 char *path; 35 char *path;
36 char *desc; 36 char *desc;
37 char *owner; 37 char *owner;
38 char *defbranch; 38 char *defbranch;
39 char *module_link; 39 char *module_link;
40 int snapshots; 40 int snapshots;
41 int enable_log_filecount;
42 int enable_log_linecount;
41}; 43};
42 44
43struct repolist { 45struct repolist {
44 int length; 46 int length;
45 int count; 47 int count;
46 struct repoinfo *repos; 48 struct repoinfo *repos;
47}; 49};
48 50
49struct commitinfo { 51struct commitinfo {
50 struct commit *commit; 52 struct commit *commit;
51 char *author; 53 char *author;
52 char *author_email; 54 char *author_email;
53 unsigned long author_date; 55 unsigned long author_date;
54 char *committer; 56 char *committer;
55 char *committer_email; 57 char *committer_email;
56 unsigned long committer_date; 58 unsigned long committer_date;
57 char *subject; 59 char *subject;
58 char *msg; 60 char *msg;
59}; 61};
60 62
61struct taginfo { 63struct taginfo {
62 char *tagger; 64 char *tagger;
63 char *tagger_email; 65 char *tagger_email;
64 int tagger_date; 66 int tagger_date;
65 char *msg; 67 char *msg;
66}; 68};
67 69
68extern const char cgit_version[]; 70extern const char cgit_version[];
69 71
70extern struct repolist cgit_repolist; 72extern struct repolist cgit_repolist;
71extern struct repoinfo *cgit_repo; 73extern struct repoinfo *cgit_repo;
72 74
73extern char *cgit_root_title; 75extern char *cgit_root_title;
74extern char *cgit_css; 76extern char *cgit_css;
75extern char *cgit_logo; 77extern char *cgit_logo;
76extern char *cgit_logo_link; 78extern char *cgit_logo_link;
77extern char *cgit_module_link; 79extern char *cgit_module_link;
78extern char *cgit_virtual_root; 80extern char *cgit_virtual_root;
79extern char *cgit_script_name; 81extern char *cgit_script_name;
80extern char *cgit_cache_root; 82extern char *cgit_cache_root;
81 83
82extern int cgit_nocache; 84extern int cgit_nocache;
83extern int cgit_snapshots; 85extern int cgit_snapshots;
86extern int cgit_enable_log_filecount;
87extern int cgit_enable_log_linecount;
84extern int cgit_max_lock_attempts; 88extern int cgit_max_lock_attempts;
85extern int cgit_cache_root_ttl; 89extern int cgit_cache_root_ttl;
86extern int cgit_cache_repo_ttl; 90extern int cgit_cache_repo_ttl;
87extern int cgit_cache_dynamic_ttl; 91extern int cgit_cache_dynamic_ttl;
88extern int cgit_cache_static_ttl; 92extern int cgit_cache_static_ttl;
89extern int cgit_cache_max_create_time; 93extern int cgit_cache_max_create_time;
90 94
91extern int cgit_max_msg_len; 95extern int cgit_max_msg_len;
92extern int cgit_max_repodesc_len; 96extern int cgit_max_repodesc_len;
93extern int cgit_max_commit_count; 97extern int cgit_max_commit_count;
94 98
95extern char *cgit_repo_name; 99extern char *cgit_repo_name;
96extern char *cgit_repo_desc; 100extern char *cgit_repo_desc;
97extern char *cgit_repo_owner; 101extern char *cgit_repo_owner;
98 102
99extern int cgit_query_has_symref; 103extern int cgit_query_has_symref;
100extern int cgit_query_has_sha1; 104extern int cgit_query_has_sha1;
101 105
102extern char *cgit_querystring; 106extern char *cgit_querystring;
103extern char *cgit_query_repo; 107extern char *cgit_query_repo;
104extern char *cgit_query_page; 108extern char *cgit_query_page;
105extern char *cgit_query_search; 109extern char *cgit_query_search;
106extern char *cgit_query_head; 110extern char *cgit_query_head;
107extern char *cgit_query_sha1; 111extern char *cgit_query_sha1;
108extern char *cgit_query_sha2; 112extern char *cgit_query_sha2;
109extern char *cgit_query_path; 113extern char *cgit_query_path;
110extern char *cgit_query_name; 114extern char *cgit_query_name;
111extern int cgit_query_ofs; 115extern int cgit_query_ofs;
112 116
113extern int htmlfd; 117extern int htmlfd;
114 118
115extern void cgit_global_config_cb(const char *name, const char *value); 119extern void cgit_global_config_cb(const char *name, const char *value);
116extern void cgit_repo_config_cb(const char *name, const char *value); 120extern void cgit_repo_config_cb(const char *name, const char *value);
117extern void cgit_querystring_cb(const char *name, const char *value); 121extern void cgit_querystring_cb(const char *name, const char *value);
118 122
119extern int chk_zero(int result, char *msg); 123extern int chk_zero(int result, char *msg);
120extern int chk_positive(int result, char *msg); 124extern int chk_positive(int result, char *msg);
121 125
122extern int hextoint(char c); 126extern int hextoint(char c);
123 127
124extern void *cgit_free_commitinfo(struct commitinfo *info); 128extern void *cgit_free_commitinfo(struct commitinfo *info);
125 129
126extern int cgit_diff_files(const unsigned char *old_sha1, 130extern int cgit_diff_files(const unsigned char *old_sha1,
127 const unsigned char *new_sha1, 131 const unsigned char *new_sha1,
128 linediff_fn fn); 132 linediff_fn fn);
129 133
130extern void cgit_diff_tree(const unsigned char *old_sha1, 134extern void cgit_diff_tree(const unsigned char *old_sha1,
131 const unsigned char *new_sha1, 135 const unsigned char *new_sha1,
132 filepair_fn fn); 136 filepair_fn fn);
133 137
134extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 138extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
135 139
136extern char *fmt(const char *format,...); 140extern char *fmt(const char *format,...);
137 141
138extern void html(const char *txt); 142extern void html(const char *txt);
139extern void htmlf(const char *format,...); 143extern void htmlf(const char *format,...);
140extern void html_txt(char *txt); 144extern void html_txt(char *txt);
141extern void html_ntxt(int len, char *txt); 145extern void html_ntxt(int len, char *txt);
142extern void html_attr(char *txt); 146extern void html_attr(char *txt);
143extern void html_hidden(char *name, char *value); 147extern void html_hidden(char *name, char *value);
144extern void html_link_open(char *url, char *title, char *class); 148extern void html_link_open(char *url, char *title, char *class);
145extern void html_link_close(void); 149extern void html_link_close(void);
146extern void html_filemode(unsigned short mode); 150extern void html_filemode(unsigned short mode);
147 151
148extern int cgit_read_config(const char *filename, configfn fn); 152extern int cgit_read_config(const char *filename, configfn fn);
149extern int cgit_parse_query(char *txt, configfn fn); 153extern int cgit_parse_query(char *txt, configfn fn);
150extern struct commitinfo *cgit_parse_commit(struct commit *commit); 154extern struct commitinfo *cgit_parse_commit(struct commit *commit);
151extern struct taginfo *cgit_parse_tag(struct tag *tag); 155extern struct taginfo *cgit_parse_tag(struct tag *tag);
152 156
153extern char *cache_safe_filename(const char *unsafe); 157extern char *cache_safe_filename(const char *unsafe);
154extern int cache_lock(struct cacheitem *item); 158extern int cache_lock(struct cacheitem *item);
155extern int cache_unlock(struct cacheitem *item); 159extern int cache_unlock(struct cacheitem *item);
156extern int cache_cancel_lock(struct cacheitem *item); 160extern int cache_cancel_lock(struct cacheitem *item);
157extern int cache_exist(struct cacheitem *item); 161extern int cache_exist(struct cacheitem *item);
158extern int cache_expired(struct cacheitem *item); 162extern int cache_expired(struct cacheitem *item);
159 163
160extern char *cgit_repourl(const char *reponame); 164extern char *cgit_repourl(const char *reponame);
161extern char *cgit_pageurl(const char *reponame, const char *pagename, 165extern char *cgit_pageurl(const char *reponame, const char *pagename,
162 const char *query); 166 const char *query);
163 167
164extern void cgit_print_error(char *msg); 168extern void cgit_print_error(char *msg);
165extern void cgit_print_date(unsigned long secs); 169extern void cgit_print_date(unsigned long secs);
166extern void cgit_print_docstart(char *title, struct cacheitem *item); 170extern void cgit_print_docstart(char *title, struct cacheitem *item);
167extern void cgit_print_docend(); 171extern void cgit_print_docend();
168extern void cgit_print_pageheader(char *title, int show_search); 172extern void cgit_print_pageheader(char *title, int show_search);
169extern void cgit_print_snapshot_start(const char *mimetype, 173extern void cgit_print_snapshot_start(const char *mimetype,
170 const char *filename, 174 const char *filename,
171 struct cacheitem *item); 175 struct cacheitem *item);
172 176
173extern void cgit_print_repolist(struct cacheitem *item); 177extern void cgit_print_repolist(struct cacheitem *item);
174extern void cgit_print_summary(); 178extern void cgit_print_summary();
175extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path); 179extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path);
176extern void cgit_print_view(const char *hex, char *path); 180extern void cgit_print_view(const char *hex, char *path);
177extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); 181extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path);
178extern void cgit_print_tree(const char *rev, const char *hex, char *path); 182extern void cgit_print_tree(const char *rev, const char *hex, char *path);
179extern void cgit_print_commit(const char *hex); 183extern void cgit_print_commit(const char *hex);
180extern void cgit_print_diff(const char *head, const char *old_hex, const char *new_hex, 184extern void cgit_print_diff(const char *head, const char *old_hex, const char *new_hex,
181 char *path); 185 char *path);
182extern void cgit_print_snapshot(struct cacheitem *item, const char *hex, 186extern void cgit_print_snapshot(struct cacheitem *item, const char *hex,
183 const char *format, const char *prefix, 187 const char *format, const char *prefix,
184 const char *filename); 188 const char *filename);
185 189
186#endif /* CGIT_H */ 190#endif /* CGIT_H */
diff --git a/cgitrc b/cgitrc
index f923cc4..eaa9ce3 100644
--- a/cgitrc
+++ b/cgitrc
@@ -1,100 +1,110 @@
1## 1##
2## cgitrc: template for /etc/cgitrc 2## cgitrc: template for /etc/cgitrc
3## 3##
4 4
5 5
6## Uncomment and set to 1 to deactivate caching of generated pages. Mostly 6## Uncomment and set to 1 to deactivate caching of generated pages. Mostly
7## usefull for testing. 7## usefull for testing.
8#nocache=0 8#nocache=0
9 9
10 10
11## Enable/disable snapshots by default. This can be overridden per repo 11## Enable/disable snapshots by default. This can be overridden per repo
12#snapshots=0 12#snapshots=0
13 13
14 14
15## Enable/disable display of 'number of files changed' in log view
16#enable-log-filecount=0
17
18
19## Enable/disable display of 'number of lines changed' in log view
20#enable-log-linecount=0
21
22
15## Specify a root for virtual urls. This makes cgit generate urls like 23## Specify a root for virtual urls. This makes cgit generate urls like
16## 24##
17## http://localhost/git/repo/log/?id=master 25## http://localhost/git/repo/log/?id=master
18## 26##
19## instead of 27## instead of
20## 28##
21## http://localhost/cgit/cgit.cgi?r=repo&p=log&id=master 29## http://localhost/cgit/cgit.cgi?r=repo&p=log&id=master
22## 30##
23## For this to work with apache, rewrite rules must be added to httpd.conf, 31## For this to work with apache, rewrite rules must be added to httpd.conf,
24## possibly looking something like this: 32## possibly looking something like this:
25## 33##
26## RewriteRule ^/git/$ /cgit/cgit.cgi [L,QSA] 34## RewriteRule ^/git/$ /cgit/cgit.cgi [L,QSA]
27## RewriteRule ^/git/([^/]+)/$ /cgit/cgit.cgi?r=$1 [L,QSA] 35## RewriteRule ^/git/([^/]+)/$ /cgit/cgit.cgi?r=$1 [L,QSA]
28## RewriteRule ^/git/([^/]+)/([^/]+)/$ /cgit/cgit.cgi?r=$1&p=$2 [L,QSA] 36## RewriteRule ^/git/([^/]+)/([^/]+)/$ /cgit/cgit.cgi?r=$1&p=$2 [L,QSA]
29## 37##
30## This setting is disabled by default. 38## This setting is disabled by default.
31#virtual-root=/git 39#virtual-root=/git
32 40
33 41
34## Set the title printed on the root page 42## Set the title printed on the root page
35#root-title=Git repository browser 43#root-title=Git repository browser
36 44
37 45
38## Link to css file 46## Link to css file
39#css=/cgit/cgit.css 47#css=/cgit/cgit.css
40 48
41 49
42## Link to logo file 50## Link to logo file
43#logo=/cgit/git-logo.png 51#logo=/cgit/git-logo.png
44 52
45 53
46## Url loaded when clicking the logo 54## Url loaded when clicking the logo
47#logo-link=http://www.kernel.org/pub/software/scm/git/docs/ 55#logo-link=http://www.kernel.org/pub/software/scm/git/docs/
48 56
49 57
50## Url loaded when clicking a submodule link 58## Url loaded when clicking a submodule link
51#module-link=./?repo=%s&page=commit&id=%s 59#module-link=./?repo=%s&page=commit&id=%s
52 60
53 61
54## Number of chars shown of repo description (in repolist view) 62## Number of chars shown of repo description (in repolist view)
55#max-repodesc-length=60 63#max-repodesc-length=60
56 64
57 65
58## Number of chars shown of commit subject message (in log view) 66## Number of chars shown of commit subject message (in log view)
59#max-message-length=60 67#max-message-length=60
60 68
61 69
62## Number of commits per page in log view 70## Number of commits per page in log view
63#max-commit-count=50 71#max-commit-count=50
64 72
65 73
66## Root of cached output 74## Root of cached output
67#cache-root=/var/cache/cgit 75#cache-root=/var/cache/cgit
68 76
69 77
70## Include another config-file 78## Include another config-file
71#include=/var/cgit/repolist 79#include=/var/cgit/repolist
72 80
73## 81##
74## Time-To-Live settings: specifies how long (in minutes) different pages 82## Time-To-Live settings: specifies how long (in minutes) different pages
75## should be cached (0 for instant expiration, -1 for immortal pages) 83## should be cached (0 for instant expiration, -1 for immortal pages)
76## 84##
77 85
78## ttl for root page 86## ttl for root page
79#cache-root-ttl=5 87#cache-root-ttl=5
80 88
81## ttl for repo summary page 89## ttl for repo summary page
82#cache-repo-ttl=5 90#cache-repo-ttl=5
83 91
84## ttl for other dynamic pages 92## ttl for other dynamic pages
85#cache-dynamic-ttl=5 93#cache-dynamic-ttl=5
86 94
87## ttl for static pages (addressed by SHA-1) 95## ttl for static pages (addressed by SHA-1)
88#cache-static-ttl=-1 96#cache-static-ttl=-1
89 97
90 98
91 99
92## Example repository entry. Required values are repo.url and repo.path (each 100## Example repository entry. Required values are repo.url and repo.path (each
93## repository section must start with repo.url). 101## repository section must start with repo.url).
94#repo.url=cgit 102#repo.url=cgit
95#repo.name=cgit 103#repo.name=cgit
96#repo.desc=the caching cgi for git 104#repo.desc=the caching cgi for git
97#repo.path=/pub/git/cgit 105#repo.path=/pub/git/cgit
98#repo.owner=Lars Hjemli 106#repo.owner=Lars Hjemli
99 #repo.snapshots=1 # override a sitewide snapshot-setting 107 #repo.snapshots=1 # override a sitewide snapshot-setting
108 #repo.enable-log-filecount=0 # override the default filecount setting
109 #repo.enable-log-linecount=0 # override the default linecount setting
100 #repo.module-link=/git/%s/commit/?id=%s # override the standard module-link 110 #repo.module-link=/git/%s/commit/?id=%s # override the standard module-link
diff --git a/shared.c b/shared.c
index 752ceac..53cd9b0 100644
--- a/shared.c
+++ b/shared.c
@@ -1,316 +1,328 @@
1/* shared.c: global vars + some callback functions 1/* shared.c: global vars + some callback functions
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 10
11struct repolist cgit_repolist; 11struct repolist cgit_repolist;
12struct repoinfo *cgit_repo; 12struct repoinfo *cgit_repo;
13 13
14char *cgit_root_title = "Git repository browser"; 14char *cgit_root_title = "Git repository browser";
15char *cgit_css = "/cgit.css"; 15char *cgit_css = "/cgit.css";
16char *cgit_logo = "/git-logo.png"; 16char *cgit_logo = "/git-logo.png";
17char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/"; 17char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/";
18char *cgit_module_link = "./?repo=%s&page=commit&id=%s"; 18char *cgit_module_link = "./?repo=%s&page=commit&id=%s";
19char *cgit_virtual_root = NULL; 19char *cgit_virtual_root = NULL;
20char *cgit_script_name = CGIT_SCRIPT_NAME; 20char *cgit_script_name = CGIT_SCRIPT_NAME;
21char *cgit_cache_root = "/var/cache/cgit"; 21char *cgit_cache_root = "/var/cache/cgit";
22 22
23int cgit_nocache = 0; 23int cgit_nocache = 0;
24int cgit_snapshots = 0; 24int cgit_snapshots = 0;
25int cgit_enable_log_filecount = 0;
26int cgit_enable_log_linecount = 0;
25int cgit_max_lock_attempts = 5; 27int cgit_max_lock_attempts = 5;
26int cgit_cache_root_ttl = 5; 28int cgit_cache_root_ttl = 5;
27int cgit_cache_repo_ttl = 5; 29int cgit_cache_repo_ttl = 5;
28int cgit_cache_dynamic_ttl = 5; 30int cgit_cache_dynamic_ttl = 5;
29int cgit_cache_static_ttl = -1; 31int cgit_cache_static_ttl = -1;
30int cgit_cache_max_create_time = 5; 32int cgit_cache_max_create_time = 5;
31 33
32int cgit_max_msg_len = 60; 34int cgit_max_msg_len = 60;
33int cgit_max_repodesc_len = 60; 35int cgit_max_repodesc_len = 60;
34int cgit_max_commit_count = 50; 36int cgit_max_commit_count = 50;
35 37
36int cgit_query_has_symref = 0; 38int cgit_query_has_symref = 0;
37int cgit_query_has_sha1 = 0; 39int cgit_query_has_sha1 = 0;
38 40
39char *cgit_querystring = NULL; 41char *cgit_querystring = NULL;
40char *cgit_query_repo = NULL; 42char *cgit_query_repo = NULL;
41char *cgit_query_page = NULL; 43char *cgit_query_page = NULL;
42char *cgit_query_head = NULL; 44char *cgit_query_head = NULL;
43char *cgit_query_search = NULL; 45char *cgit_query_search = NULL;
44char *cgit_query_sha1 = NULL; 46char *cgit_query_sha1 = NULL;
45char *cgit_query_sha2 = NULL; 47char *cgit_query_sha2 = NULL;
46char *cgit_query_path = NULL; 48char *cgit_query_path = NULL;
47char *cgit_query_name = NULL; 49char *cgit_query_name = NULL;
48int cgit_query_ofs = 0; 50int cgit_query_ofs = 0;
49 51
50int htmlfd = 0; 52int htmlfd = 0;
51 53
52int chk_zero(int result, char *msg) 54int chk_zero(int result, char *msg)
53{ 55{
54 if (result != 0) 56 if (result != 0)
55 die("%s: %s", msg, strerror(errno)); 57 die("%s: %s", msg, strerror(errno));
56 return result; 58 return result;
57} 59}
58 60
59int chk_positive(int result, char *msg) 61int chk_positive(int result, char *msg)
60{ 62{
61 if (result <= 0) 63 if (result <= 0)
62 die("%s: %s", msg, strerror(errno)); 64 die("%s: %s", msg, strerror(errno));
63 return result; 65 return result;
64} 66}
65 67
66struct repoinfo *add_repo(const char *url) 68struct repoinfo *add_repo(const char *url)
67{ 69{
68 struct repoinfo *ret; 70 struct repoinfo *ret;
69 71
70 if (++cgit_repolist.count > cgit_repolist.length) { 72 if (++cgit_repolist.count > cgit_repolist.length) {
71 if (cgit_repolist.length == 0) 73 if (cgit_repolist.length == 0)
72 cgit_repolist.length = 8; 74 cgit_repolist.length = 8;
73 else 75 else
74 cgit_repolist.length *= 2; 76 cgit_repolist.length *= 2;
75 cgit_repolist.repos = xrealloc(cgit_repolist.repos, 77 cgit_repolist.repos = xrealloc(cgit_repolist.repos,
76 cgit_repolist.length * 78 cgit_repolist.length *
77 sizeof(struct repoinfo)); 79 sizeof(struct repoinfo));
78 } 80 }
79 81
80 ret = &cgit_repolist.repos[cgit_repolist.count-1]; 82 ret = &cgit_repolist.repos[cgit_repolist.count-1];
81 ret->url = xstrdup(url); 83 ret->url = xstrdup(url);
82 ret->name = ret->url; 84 ret->name = ret->url;
83 ret->path = NULL; 85 ret->path = NULL;
84 ret->desc = NULL; 86 ret->desc = NULL;
85 ret->owner = NULL; 87 ret->owner = NULL;
86 ret->defbranch = "master"; 88 ret->defbranch = "master";
87 ret->snapshots = cgit_snapshots; 89 ret->snapshots = cgit_snapshots;
90 ret->enable_log_filecount = cgit_enable_log_filecount;
91 ret->enable_log_linecount = cgit_enable_log_linecount;
88 ret->module_link = cgit_module_link; 92 ret->module_link = cgit_module_link;
89 return ret; 93 return ret;
90} 94}
91 95
92void cgit_global_config_cb(const char *name, const char *value) 96void cgit_global_config_cb(const char *name, const char *value)
93{ 97{
94 if (!strcmp(name, "root-title")) 98 if (!strcmp(name, "root-title"))
95 cgit_root_title = xstrdup(value); 99 cgit_root_title = xstrdup(value);
96 else if (!strcmp(name, "css")) 100 else if (!strcmp(name, "css"))
97 cgit_css = xstrdup(value); 101 cgit_css = xstrdup(value);
98 else if (!strcmp(name, "logo")) 102 else if (!strcmp(name, "logo"))
99 cgit_logo = xstrdup(value); 103 cgit_logo = xstrdup(value);
100 else if (!strcmp(name, "logo-link")) 104 else if (!strcmp(name, "logo-link"))
101 cgit_logo_link = xstrdup(value); 105 cgit_logo_link = xstrdup(value);
102 else if (!strcmp(name, "module-link")) 106 else if (!strcmp(name, "module-link"))
103 cgit_module_link = xstrdup(value); 107 cgit_module_link = xstrdup(value);
104 else if (!strcmp(name, "virtual-root")) 108 else if (!strcmp(name, "virtual-root"))
105 cgit_virtual_root = xstrdup(value); 109 cgit_virtual_root = xstrdup(value);
106 else if (!strcmp(name, "nocache")) 110 else if (!strcmp(name, "nocache"))
107 cgit_nocache = atoi(value); 111 cgit_nocache = atoi(value);
108 else if (!strcmp(name, "snapshots")) 112 else if (!strcmp(name, "snapshots"))
109 cgit_snapshots = atoi(value); 113 cgit_snapshots = atoi(value);
114 else if (!strcmp(name, "enable-log-filecount"))
115 cgit_enable_log_filecount = atoi(value);
116 else if (!strcmp(name, "enable-log-linecount"))
117 cgit_enable_log_linecount = atoi(value);
110 else if (!strcmp(name, "cache-root")) 118 else if (!strcmp(name, "cache-root"))
111 cgit_cache_root = xstrdup(value); 119 cgit_cache_root = xstrdup(value);
112 else if (!strcmp(name, "cache-root-ttl")) 120 else if (!strcmp(name, "cache-root-ttl"))
113 cgit_cache_root_ttl = atoi(value); 121 cgit_cache_root_ttl = atoi(value);
114 else if (!strcmp(name, "cache-repo-ttl")) 122 else if (!strcmp(name, "cache-repo-ttl"))
115 cgit_cache_repo_ttl = atoi(value); 123 cgit_cache_repo_ttl = atoi(value);
116 else if (!strcmp(name, "cache-static-ttl")) 124 else if (!strcmp(name, "cache-static-ttl"))
117 cgit_cache_static_ttl = atoi(value); 125 cgit_cache_static_ttl = atoi(value);
118 else if (!strcmp(name, "cache-dynamic-ttl")) 126 else if (!strcmp(name, "cache-dynamic-ttl"))
119 cgit_cache_dynamic_ttl = atoi(value); 127 cgit_cache_dynamic_ttl = atoi(value);
120 else if (!strcmp(name, "max-message-length")) 128 else if (!strcmp(name, "max-message-length"))
121 cgit_max_msg_len = atoi(value); 129 cgit_max_msg_len = atoi(value);
122 else if (!strcmp(name, "max-repodesc-length")) 130 else if (!strcmp(name, "max-repodesc-length"))
123 cgit_max_repodesc_len = atoi(value); 131 cgit_max_repodesc_len = atoi(value);
124 else if (!strcmp(name, "max-commit-count")) 132 else if (!strcmp(name, "max-commit-count"))
125 cgit_max_commit_count = atoi(value); 133 cgit_max_commit_count = atoi(value);
126 else if (!strcmp(name, "repo.url")) 134 else if (!strcmp(name, "repo.url"))
127 cgit_repo = add_repo(value); 135 cgit_repo = add_repo(value);
128 else if (!strcmp(name, "repo.name")) 136 else if (!strcmp(name, "repo.name"))
129 cgit_repo->name = xstrdup(value); 137 cgit_repo->name = xstrdup(value);
130 else if (cgit_repo && !strcmp(name, "repo.path")) 138 else if (cgit_repo && !strcmp(name, "repo.path"))
131 cgit_repo->path = xstrdup(value); 139 cgit_repo->path = xstrdup(value);
132 else if (cgit_repo && !strcmp(name, "repo.desc")) 140 else if (cgit_repo && !strcmp(name, "repo.desc"))
133 cgit_repo->desc = xstrdup(value); 141 cgit_repo->desc = xstrdup(value);
134 else if (cgit_repo && !strcmp(name, "repo.owner")) 142 else if (cgit_repo && !strcmp(name, "repo.owner"))
135 cgit_repo->owner = xstrdup(value); 143 cgit_repo->owner = xstrdup(value);
136 else if (cgit_repo && !strcmp(name, "repo.defbranch")) 144 else if (cgit_repo && !strcmp(name, "repo.defbranch"))
137 cgit_repo->defbranch = xstrdup(value); 145 cgit_repo->defbranch = xstrdup(value);
138 else if (cgit_repo && !strcmp(name, "repo.snapshots")) 146 else if (cgit_repo && !strcmp(name, "repo.snapshots"))
139 cgit_repo->snapshots = atoi(value); 147 cgit_repo->snapshots = cgit_snapshots * atoi(value);
148 else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount"))
149 cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value);
150 else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount"))
151 cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value);
140 else if (cgit_repo && !strcmp(name, "repo.module-link")) 152 else if (cgit_repo && !strcmp(name, "repo.module-link"))
141 cgit_repo->module_link= xstrdup(value); 153 cgit_repo->module_link= xstrdup(value);
142 else if (!strcmp(name, "include")) 154 else if (!strcmp(name, "include"))
143 cgit_read_config(value, cgit_global_config_cb); 155 cgit_read_config(value, cgit_global_config_cb);
144} 156}
145 157
146void cgit_querystring_cb(const char *name, const char *value) 158void cgit_querystring_cb(const char *name, const char *value)
147{ 159{
148 if (!strcmp(name,"r")) { 160 if (!strcmp(name,"r")) {
149 cgit_query_repo = xstrdup(value); 161 cgit_query_repo = xstrdup(value);
150 } else if (!strcmp(name, "p")) { 162 } else if (!strcmp(name, "p")) {
151 cgit_query_page = xstrdup(value); 163 cgit_query_page = xstrdup(value);
152 } else if (!strcmp(name, "q")) { 164 } else if (!strcmp(name, "q")) {
153 cgit_query_search = xstrdup(value); 165 cgit_query_search = xstrdup(value);
154 } else if (!strcmp(name, "h")) { 166 } else if (!strcmp(name, "h")) {
155 cgit_query_head = xstrdup(value); 167 cgit_query_head = xstrdup(value);
156 cgit_query_has_symref = 1; 168 cgit_query_has_symref = 1;
157 } else if (!strcmp(name, "id")) { 169 } else if (!strcmp(name, "id")) {
158 cgit_query_sha1 = xstrdup(value); 170 cgit_query_sha1 = xstrdup(value);
159 cgit_query_has_sha1 = 1; 171 cgit_query_has_sha1 = 1;
160 } else if (!strcmp(name, "id2")) { 172 } else if (!strcmp(name, "id2")) {
161 cgit_query_sha2 = xstrdup(value); 173 cgit_query_sha2 = xstrdup(value);
162 cgit_query_has_sha1 = 1; 174 cgit_query_has_sha1 = 1;
163 } else if (!strcmp(name, "ofs")) { 175 } else if (!strcmp(name, "ofs")) {
164 cgit_query_ofs = atoi(value); 176 cgit_query_ofs = atoi(value);
165 } else if (!strcmp(name, "path")) { 177 } else if (!strcmp(name, "path")) {
166 cgit_query_path = xstrdup(value); 178 cgit_query_path = xstrdup(value);
167 } else if (!strcmp(name, "name")) { 179 } else if (!strcmp(name, "name")) {
168 cgit_query_name = xstrdup(value); 180 cgit_query_name = xstrdup(value);
169 } 181 }
170} 182}
171 183
172void *cgit_free_commitinfo(struct commitinfo *info) 184void *cgit_free_commitinfo(struct commitinfo *info)
173{ 185{
174 free(info->author); 186 free(info->author);
175 free(info->author_email); 187 free(info->author_email);
176 free(info->committer); 188 free(info->committer);
177 free(info->committer_email); 189 free(info->committer_email);
178 free(info->subject); 190 free(info->subject);
179 free(info); 191 free(info);
180 return NULL; 192 return NULL;
181} 193}
182 194
183int hextoint(char c) 195int hextoint(char c)
184{ 196{
185 if (c >= 'a' && c <= 'f') 197 if (c >= 'a' && c <= 'f')
186 return 10 + c - 'a'; 198 return 10 + c - 'a';
187 else if (c >= 'A' && c <= 'F') 199 else if (c >= 'A' && c <= 'F')
188 return 10 + c - 'A'; 200 return 10 + c - 'A';
189 else if (c >= '0' && c <= '9') 201 else if (c >= '0' && c <= '9')
190 return c - '0'; 202 return c - '0';
191 else 203 else
192 return -1; 204 return -1;
193} 205}
194 206
195void cgit_diff_tree_cb(struct diff_queue_struct *q, 207void cgit_diff_tree_cb(struct diff_queue_struct *q,
196 struct diff_options *options, void *data) 208 struct diff_options *options, void *data)
197{ 209{
198 int i; 210 int i;
199 211
200 for (i = 0; i < q->nr; i++) { 212 for (i = 0; i < q->nr; i++) {
201 if (q->queue[i]->status == 'U') 213 if (q->queue[i]->status == 'U')
202 continue; 214 continue;
203 ((filepair_fn)data)(q->queue[i]); 215 ((filepair_fn)data)(q->queue[i]);
204 } 216 }
205} 217}
206 218
207static int load_mmfile(mmfile_t *file, const unsigned char *sha1) 219static int load_mmfile(mmfile_t *file, const unsigned char *sha1)
208{ 220{
209 enum object_type type; 221 enum object_type type;
210 222
211 if (is_null_sha1(sha1)) { 223 if (is_null_sha1(sha1)) {
212 file->ptr = (char *)""; 224 file->ptr = (char *)"";
213 file->size = 0; 225 file->size = 0;
214 } else { 226 } else {
215 file->ptr = read_sha1_file(sha1, &type, &file->size); 227 file->ptr = read_sha1_file(sha1, &type, &file->size);
216 } 228 }
217 return 1; 229 return 1;
218} 230}
219 231
220/* 232/*
221 * Receive diff-buffers from xdiff and concatenate them as 233 * Receive diff-buffers from xdiff and concatenate them as
222 * needed across multiple callbacks. 234 * needed across multiple callbacks.
223 * 235 *
224 * This is basically a copy of xdiff-interface.c/xdiff_outf(), 236 * This is basically a copy of xdiff-interface.c/xdiff_outf(),
225 * ripped from git and modified to use globals instead of 237 * ripped from git and modified to use globals instead of
226 * a special callback-struct. 238 * a special callback-struct.
227 */ 239 */
228char *diffbuf = NULL; 240char *diffbuf = NULL;
229int buflen = 0; 241int buflen = 0;
230 242
231int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf) 243int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)
232{ 244{
233 int i; 245 int i;
234 246
235 for (i = 0; i < nbuf; i++) { 247 for (i = 0; i < nbuf; i++) {
236 if (mb[i].ptr[mb[i].size-1] != '\n') { 248 if (mb[i].ptr[mb[i].size-1] != '\n') {
237 /* Incomplete line */ 249 /* Incomplete line */
238 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 250 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
239 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 251 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
240 buflen += mb[i].size; 252 buflen += mb[i].size;
241 continue; 253 continue;
242 } 254 }
243 255
244 /* we have a complete line */ 256 /* we have a complete line */
245 if (!diffbuf) { 257 if (!diffbuf) {
246 ((linediff_fn)priv)(mb[i].ptr, mb[i].size); 258 ((linediff_fn)priv)(mb[i].ptr, mb[i].size);
247 continue; 259 continue;
248 } 260 }
249 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 261 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
250 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 262 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
251 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size); 263 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size);
252 free(diffbuf); 264 free(diffbuf);
253 diffbuf = NULL; 265 diffbuf = NULL;
254 buflen = 0; 266 buflen = 0;
255 } 267 }
256 if (diffbuf) { 268 if (diffbuf) {
257 ((linediff_fn)priv)(diffbuf, buflen); 269 ((linediff_fn)priv)(diffbuf, buflen);
258 free(diffbuf); 270 free(diffbuf);
259 diffbuf = NULL; 271 diffbuf = NULL;
260 buflen = 0; 272 buflen = 0;
261 } 273 }
262 return 0; 274 return 0;
263} 275}
264 276
265int cgit_diff_files(const unsigned char *old_sha1, 277int cgit_diff_files(const unsigned char *old_sha1,
266 const unsigned char *new_sha1, 278 const unsigned char *new_sha1,
267 linediff_fn fn) 279 linediff_fn fn)
268{ 280{
269 mmfile_t file1, file2; 281 mmfile_t file1, file2;
270 xpparam_t diff_params; 282 xpparam_t diff_params;
271 xdemitconf_t emit_params; 283 xdemitconf_t emit_params;
272 xdemitcb_t emit_cb; 284 xdemitcb_t emit_cb;
273 285
274 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1)) 286 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1))
275 return 1; 287 return 1;
276 288
277 diff_params.flags = XDF_NEED_MINIMAL; 289 diff_params.flags = XDF_NEED_MINIMAL;
278 emit_params.ctxlen = 3; 290 emit_params.ctxlen = 3;
279 emit_params.flags = XDL_EMIT_FUNCNAMES; 291 emit_params.flags = XDL_EMIT_FUNCNAMES;
280 emit_cb.outf = filediff_cb; 292 emit_cb.outf = filediff_cb;
281 emit_cb.priv = fn; 293 emit_cb.priv = fn;
282 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); 294 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb);
283 return 0; 295 return 0;
284} 296}
285 297
286void cgit_diff_tree(const unsigned char *old_sha1, 298void cgit_diff_tree(const unsigned char *old_sha1,
287 const unsigned char *new_sha1, 299 const unsigned char *new_sha1,
288 filepair_fn fn) 300 filepair_fn fn)
289{ 301{
290 struct diff_options opt; 302 struct diff_options opt;
291 int ret; 303 int ret;
292 304
293 diff_setup(&opt); 305 diff_setup(&opt);
294 opt.output_format = DIFF_FORMAT_CALLBACK; 306 opt.output_format = DIFF_FORMAT_CALLBACK;
295 opt.detect_rename = 1; 307 opt.detect_rename = 1;
296 opt.recursive = 1; 308 opt.recursive = 1;
297 opt.format_callback = cgit_diff_tree_cb; 309 opt.format_callback = cgit_diff_tree_cb;
298 opt.format_callback_data = fn; 310 opt.format_callback_data = fn;
299 diff_setup_done(&opt); 311 diff_setup_done(&opt);
300 312
301 if (old_sha1) 313 if (old_sha1)
302 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt); 314 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt);
303 else 315 else
304 ret = diff_root_tree_sha1(new_sha1, "", &opt); 316 ret = diff_root_tree_sha1(new_sha1, "", &opt);
305 diffcore_std(&opt); 317 diffcore_std(&opt);
306 diff_flush(&opt); 318 diff_flush(&opt);
307} 319}
308 320
309void cgit_diff_commit(struct commit *commit, filepair_fn fn) 321void cgit_diff_commit(struct commit *commit, filepair_fn fn)
310{ 322{
311 unsigned char *old_sha1 = NULL; 323 unsigned char *old_sha1 = NULL;
312 324
313 if (commit->parents) 325 if (commit->parents)
314 old_sha1 = commit->parents->item->object.sha1; 326 old_sha1 = commit->parents->item->object.sha1;
315 cgit_diff_tree(old_sha1, commit->object.sha1, fn); 327 cgit_diff_tree(old_sha1, commit->object.sha1, fn);
316} 328}
diff --git a/ui-log.c b/ui-log.c
index 9d0ec02..4237921 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -1,123 +1,132 @@
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 10
11int files, lines; 11int files, lines;
12 12
13void count_lines(char *line, int size) 13void count_lines(char *line, int size)
14{ 14{
15 if (size>0 && (line[0] == '+' || line[0] == '-')) 15 if (size>0 && (line[0] == '+' || line[0] == '-'))
16 lines++; 16 lines++;
17} 17}
18 18
19void inspect_files(struct diff_filepair *pair) 19void inspect_files(struct diff_filepair *pair)
20{ 20{
21 files++; 21 files++;
22 cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines); 22 if (cgit_repo->enable_log_linecount)
23 cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines);
23} 24}
24 25
25void print_commit(struct commit *commit) 26void print_commit(struct commit *commit)
26{ 27{
27 char buf[32]; 28 char buf[32];
28 struct commitinfo *info; 29 struct commitinfo *info;
29 struct tm *time; 30 struct tm *time;
30 31
31 info = cgit_parse_commit(commit); 32 info = cgit_parse_commit(commit);
32 time = gmtime(&commit->date); 33 time = gmtime(&commit->date);
33 html("<tr><td>"); 34 html("<tr><td>");
34 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", time); 35 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", time);
35 html_txt(buf); 36 html_txt(buf);
36 html("</td><td>"); 37 html("</td><td>");
37 char *qry = fmt("h=%s", sha1_to_hex(commit->object.sha1)); 38 char *qry = fmt("h=%s", sha1_to_hex(commit->object.sha1));
38 char *url = cgit_pageurl(cgit_query_repo, "commit", qry); 39 char *url = cgit_pageurl(cgit_query_repo, "commit", qry);
39 html_link_open(url, NULL, NULL); 40 html_link_open(url, NULL, NULL);
40 html_ntxt(cgit_max_msg_len, info->subject); 41 html_ntxt(cgit_max_msg_len, info->subject);
41 html_link_close(); 42 html_link_close();
42 files = 0; 43 if (cgit_repo->enable_log_filecount) {
43 lines = 0; 44 files = 0;
44 cgit_diff_commit(commit, inspect_files); 45 lines = 0;
45 html("</td><td class='right'>"); 46 cgit_diff_commit(commit, inspect_files);
46 htmlf("%d", files); 47 html("</td><td class='right'>");
47 html("</td><td class='right'>"); 48 htmlf("%d", files);
48 htmlf("%d", lines); 49 if (cgit_repo->enable_log_linecount) {
50 html("</td><td class='right'>");
51 htmlf("%d", lines);
52 }
53 }
49 html("</td><td>"); 54 html("</td><td>");
50 html_txt(info->author); 55 html_txt(info->author);
51 html("</td></tr>\n"); 56 html("</td></tr>\n");
52 cgit_free_commitinfo(info); 57 cgit_free_commitinfo(info);
53} 58}
54 59
55 60
56void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path) 61void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path)
57{ 62{
58 struct rev_info rev; 63 struct rev_info rev;
59 struct commit *commit; 64 struct commit *commit;
60 const char *argv[] = {NULL, tip, NULL, NULL, NULL}; 65 const char *argv[] = {NULL, tip, NULL, NULL, NULL};
61 int argc = 2; 66 int argc = 2;
62 int i; 67 int i;
63 68
64 if (grep) 69 if (grep)
65 argv[argc++] = fmt("--grep=%s", grep); 70 argv[argc++] = fmt("--grep=%s", grep);
66 if (path) { 71 if (path) {
67 argv[argc++] = "--"; 72 argv[argc++] = "--";
68 argv[argc++] = path; 73 argv[argc++] = path;
69 } 74 }
70 init_revisions(&rev, NULL); 75 init_revisions(&rev, NULL);
71 rev.abbrev = DEFAULT_ABBREV; 76 rev.abbrev = DEFAULT_ABBREV;
72 rev.commit_format = CMIT_FMT_DEFAULT; 77 rev.commit_format = CMIT_FMT_DEFAULT;
73 rev.verbose_header = 1; 78 rev.verbose_header = 1;
74 rev.show_root_diff = 0; 79 rev.show_root_diff = 0;
75 setup_revisions(argc, argv, &rev, NULL); 80 setup_revisions(argc, argv, &rev, NULL);
76 if (rev.grep_filter) { 81 if (rev.grep_filter) {
77 rev.grep_filter->regflags |= REG_ICASE; 82 rev.grep_filter->regflags |= REG_ICASE;
78 compile_grep_patterns(rev.grep_filter); 83 compile_grep_patterns(rev.grep_filter);
79 } 84 }
80 prepare_revision_walk(&rev); 85 prepare_revision_walk(&rev);
81 86
82 html("<table class='list nowrap'>"); 87 html("<table class='list nowrap'>");
83 html("<tr class='nohover'><th class='left'>Date</th>" 88 html("<tr class='nohover'><th class='left'>Date</th>"
84 "<th class='left'>Message</th>" 89 "<th class='left'>Message</th>");
85 "<th class='left'>Files</th>" 90
86 "<th class='left'>Lines</th>" 91 if (cgit_repo->enable_log_filecount) {
87 "<th class='left'>Author</th></tr>\n"); 92 html("<th class='left'>Files</th>");
93 if (cgit_repo->enable_log_linecount)
94 html("<th class='left'>Lines</th>");
95 }
96 html("<th class='left'>Author</th></tr>\n");
88 97
89 if (ofs<0) 98 if (ofs<0)
90 ofs = 0; 99 ofs = 0;
91 100
92 for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) { 101 for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) {
93 free(commit->buffer); 102 free(commit->buffer);
94 commit->buffer = NULL; 103 commit->buffer = NULL;
95 free_commit_list(commit->parents); 104 free_commit_list(commit->parents);
96 commit->parents = NULL; 105 commit->parents = NULL;
97 } 106 }
98 107
99 for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) { 108 for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) {
100 print_commit(commit); 109 print_commit(commit);
101 free(commit->buffer); 110 free(commit->buffer);
102 commit->buffer = NULL; 111 commit->buffer = NULL;
103 free_commit_list(commit->parents); 112 free_commit_list(commit->parents);
104 commit->parents = NULL; 113 commit->parents = NULL;
105 } 114 }
106 html("</table>\n"); 115 html("</table>\n");
107 116
108 html("<div class='pager'>"); 117 html("<div class='pager'>");
109 if (ofs > 0) { 118 if (ofs > 0) {
110 html("&nbsp;<a href='"); 119 html("&nbsp;<a href='");
111 html(cgit_pageurl(cgit_query_repo, cgit_query_page, 120 html(cgit_pageurl(cgit_query_repo, cgit_query_page,
112 fmt("h=%s&ofs=%d", tip, ofs-cnt))); 121 fmt("h=%s&ofs=%d", tip, ofs-cnt)));
113 html("'>[prev]</a>&nbsp;"); 122 html("'>[prev]</a>&nbsp;");
114 } 123 }
115 124
116 if ((commit = get_revision(&rev)) != NULL) { 125 if ((commit = get_revision(&rev)) != NULL) {
117 html("&nbsp;<a href='"); 126 html("&nbsp;<a href='");
118 html(cgit_pageurl(cgit_query_repo, "log", 127 html(cgit_pageurl(cgit_query_repo, "log",
119 fmt("h=%s&ofs=%d", tip, ofs+cnt))); 128 fmt("h=%s&ofs=%d", tip, ofs+cnt)));
120 html("'>[next]</a>&nbsp;"); 129 html("'>[next]</a>&nbsp;");
121 } 130 }
122 html("</div>"); 131 html("</div>");
123} 132}