summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2007-05-15 22:26:23 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2007-05-15 22:26:23 (UTC)
commita2ddc10479ec463708e422ca5ce7ec02c22a7d02 (patch) (unidiff)
treee099ad98a79d61eb6e368a7e7972700f0e65b9ae
parentb28b105ec172b258ae5d629381a5890697c2f938 (diff)
downloadcgit-a2ddc10479ec463708e422ca5ce7ec02c22a7d02.zip
cgit-a2ddc10479ec463708e422ca5ce7ec02c22a7d02.tar.gz
cgit-a2ddc10479ec463708e422ca5ce7ec02c22a7d02.tar.bz2
Change commit-view to expect h parameter, not id
The change makes the commit-page benefit from repo.defbranch. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c2
-rw-r--r--ui-commit.c2
-rw-r--r--ui-log.c3
-rw-r--r--ui-summary.c16
4 files changed, 13 insertions, 10 deletions
diff --git a/cgit.c b/cgit.c
index b282a67..9b4815d 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,265 +1,265 @@
1/* cgit.c: cgi for the git scm 1/* cgit.c: cgi for the git scm
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
11const char cgit_version[] = CGIT_VERSION; 11const char cgit_version[] = CGIT_VERSION;
12 12
13 13
14static struct repoinfo *cgit_get_repoinfo(char *url) 14static struct repoinfo *cgit_get_repoinfo(char *url)
15{ 15{
16 int i; 16 int i;
17 struct repoinfo *repo; 17 struct repoinfo *repo;
18 18
19 for (i=0; i<cgit_repolist.count; i++) { 19 for (i=0; i<cgit_repolist.count; i++) {
20 repo = &cgit_repolist.repos[i]; 20 repo = &cgit_repolist.repos[i];
21 if (!strcmp(repo->url, url)) 21 if (!strcmp(repo->url, url))
22 return repo; 22 return repo;
23 } 23 }
24 return NULL; 24 return NULL;
25} 25}
26 26
27 27
28static int cgit_prepare_cache(struct cacheitem *item) 28static int cgit_prepare_cache(struct cacheitem *item)
29{ 29{
30 if (!cgit_query_repo) { 30 if (!cgit_query_repo) {
31 item->name = xstrdup(fmt("%s/index.html", cgit_cache_root)); 31 item->name = xstrdup(fmt("%s/index.html", cgit_cache_root));
32 item->ttl = cgit_cache_root_ttl; 32 item->ttl = cgit_cache_root_ttl;
33 return 1; 33 return 1;
34 } 34 }
35 cgit_repo = cgit_get_repoinfo(cgit_query_repo); 35 cgit_repo = cgit_get_repoinfo(cgit_query_repo);
36 if (!cgit_repo) { 36 if (!cgit_repo) {
37 char *title = fmt("%s - %s", cgit_root_title, "Bad request"); 37 char *title = fmt("%s - %s", cgit_root_title, "Bad request");
38 cgit_print_docstart(title, item); 38 cgit_print_docstart(title, item);
39 cgit_print_pageheader(title, 0); 39 cgit_print_pageheader(title, 0);
40 cgit_print_error(fmt("Unknown repo: %s", cgit_query_repo)); 40 cgit_print_error(fmt("Unknown repo: %s", cgit_query_repo));
41 cgit_print_docend(); 41 cgit_print_docend();
42 return 0; 42 return 0;
43 } 43 }
44 44
45 if (!cgit_query_page) { 45 if (!cgit_query_page) {
46 item->name = xstrdup(fmt("%s/%s/index.html", cgit_cache_root, 46 item->name = xstrdup(fmt("%s/%s/index.html", cgit_cache_root,
47 cgit_repo->url)); 47 cgit_repo->url));
48 item->ttl = cgit_cache_repo_ttl; 48 item->ttl = cgit_cache_repo_ttl;
49 } else { 49 } else {
50 item->name = xstrdup(fmt("%s/%s/%s/%s.html", cgit_cache_root, 50 item->name = xstrdup(fmt("%s/%s/%s/%s.html", cgit_cache_root,
51 cgit_repo->url, cgit_query_page, 51 cgit_repo->url, cgit_query_page,
52 cache_safe_filename(cgit_querystring))); 52 cache_safe_filename(cgit_querystring)));
53 if (cgit_query_has_symref) 53 if (cgit_query_has_symref)
54 item->ttl = cgit_cache_dynamic_ttl; 54 item->ttl = cgit_cache_dynamic_ttl;
55 else if (cgit_query_has_sha1) 55 else if (cgit_query_has_sha1)
56 item->ttl = cgit_cache_static_ttl; 56 item->ttl = cgit_cache_static_ttl;
57 else 57 else
58 item->ttl = cgit_cache_repo_ttl; 58 item->ttl = cgit_cache_repo_ttl;
59 } 59 }
60 return 1; 60 return 1;
61} 61}
62 62
63static void cgit_print_repo_page(struct cacheitem *item) 63static void cgit_print_repo_page(struct cacheitem *item)
64{ 64{
65 char *title; 65 char *title;
66 int show_search; 66 int show_search;
67 67
68 if (!cgit_query_head) 68 if (!cgit_query_head)
69 cgit_query_head = cgit_repo->defbranch; 69 cgit_query_head = cgit_repo->defbranch;
70 70
71 if (chdir(cgit_repo->path)) { 71 if (chdir(cgit_repo->path)) {
72 title = fmt("%s - %s", cgit_root_title, "Bad request"); 72 title = fmt("%s - %s", cgit_root_title, "Bad request");
73 cgit_print_docstart(title, item); 73 cgit_print_docstart(title, item);
74 cgit_print_pageheader(title, 0); 74 cgit_print_pageheader(title, 0);
75 cgit_print_error(fmt("Unable to scan repository: %s", 75 cgit_print_error(fmt("Unable to scan repository: %s",
76 strerror(errno))); 76 strerror(errno)));
77 cgit_print_docend(); 77 cgit_print_docend();
78 return; 78 return;
79 } 79 }
80 80
81 title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc); 81 title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc);
82 show_search = 0; 82 show_search = 0;
83 setenv("GIT_DIR", cgit_repo->path, 1); 83 setenv("GIT_DIR", cgit_repo->path, 1);
84 84
85 if (cgit_query_page) { 85 if (cgit_query_page) {
86 if (cgit_repo->snapshots && !strcmp(cgit_query_page, "snapshot")) { 86 if (cgit_repo->snapshots && !strcmp(cgit_query_page, "snapshot")) {
87 cgit_print_snapshot(item, cgit_query_sha1, "zip", 87 cgit_print_snapshot(item, cgit_query_sha1, "zip",
88 cgit_repo->url, cgit_query_name); 88 cgit_repo->url, cgit_query_name);
89 return; 89 return;
90 } 90 }
91 if (!strcmp(cgit_query_page, "blob")) { 91 if (!strcmp(cgit_query_page, "blob")) {
92 cgit_print_blob(item, cgit_query_sha1, cgit_query_path); 92 cgit_print_blob(item, cgit_query_sha1, cgit_query_path);
93 return; 93 return;
94 } 94 }
95 } 95 }
96 96
97 if (cgit_query_page && !strcmp(cgit_query_page, "log")) 97 if (cgit_query_page && !strcmp(cgit_query_page, "log"))
98 show_search = 1; 98 show_search = 1;
99 99
100 cgit_print_docstart(title, item); 100 cgit_print_docstart(title, item);
101 101
102 102
103 if (!cgit_query_page) { 103 if (!cgit_query_page) {
104 cgit_print_pageheader("summary", show_search); 104 cgit_print_pageheader("summary", show_search);
105 cgit_print_summary(); 105 cgit_print_summary();
106 cgit_print_docend(); 106 cgit_print_docend();
107 return; 107 return;
108 } 108 }
109 109
110 cgit_print_pageheader(cgit_query_page, show_search); 110 cgit_print_pageheader(cgit_query_page, show_search);
111 111
112 if (!strcmp(cgit_query_page, "log")) { 112 if (!strcmp(cgit_query_page, "log")) {
113 cgit_print_log(cgit_query_head, cgit_query_ofs, 113 cgit_print_log(cgit_query_head, cgit_query_ofs,
114 cgit_max_commit_count, cgit_query_search, 114 cgit_max_commit_count, cgit_query_search,
115 cgit_query_path); 115 cgit_query_path);
116 } else if (!strcmp(cgit_query_page, "tree")) { 116 } else if (!strcmp(cgit_query_page, "tree")) {
117 cgit_print_tree(cgit_query_head, cgit_query_sha1, cgit_query_path); 117 cgit_print_tree(cgit_query_head, cgit_query_sha1, cgit_query_path);
118 } else if (!strcmp(cgit_query_page, "commit")) { 118 } else if (!strcmp(cgit_query_page, "commit")) {
119 cgit_print_commit(cgit_query_sha1); 119 cgit_print_commit(cgit_query_head);
120 } else if (!strcmp(cgit_query_page, "view")) { 120 } else if (!strcmp(cgit_query_page, "view")) {
121 cgit_print_view(cgit_query_sha1, cgit_query_path); 121 cgit_print_view(cgit_query_sha1, cgit_query_path);
122 } else if (!strcmp(cgit_query_page, "diff")) { 122 } else if (!strcmp(cgit_query_page, "diff")) {
123 cgit_print_diff(cgit_query_sha1, cgit_query_sha2, cgit_query_path); 123 cgit_print_diff(cgit_query_sha1, cgit_query_sha2, cgit_query_path);
124 } else { 124 } else {
125 cgit_print_error("Invalid request"); 125 cgit_print_error("Invalid request");
126 } 126 }
127 cgit_print_docend(); 127 cgit_print_docend();
128} 128}
129 129
130static void cgit_fill_cache(struct cacheitem *item, int use_cache) 130static void cgit_fill_cache(struct cacheitem *item, int use_cache)
131{ 131{
132 static char buf[PATH_MAX]; 132 static char buf[PATH_MAX];
133 int stdout2; 133 int stdout2;
134 134
135 getcwd(buf, sizeof(buf)); 135 getcwd(buf, sizeof(buf));
136 item->st.st_mtime = time(NULL); 136 item->st.st_mtime = time(NULL);
137 137
138 if (use_cache) { 138 if (use_cache) {
139 stdout2 = chk_positive(dup(STDOUT_FILENO), 139 stdout2 = chk_positive(dup(STDOUT_FILENO),
140 "Preserving STDOUT"); 140 "Preserving STDOUT");
141 chk_zero(close(STDOUT_FILENO), "Closing STDOUT"); 141 chk_zero(close(STDOUT_FILENO), "Closing STDOUT");
142 chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)"); 142 chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)");
143 } 143 }
144 144
145 if (cgit_query_repo) 145 if (cgit_query_repo)
146 cgit_print_repo_page(item); 146 cgit_print_repo_page(item);
147 else 147 else
148 cgit_print_repolist(item); 148 cgit_print_repolist(item);
149 149
150 if (use_cache) { 150 if (use_cache) {
151 chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT"); 151 chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT");
152 chk_positive(dup2(stdout2, STDOUT_FILENO), 152 chk_positive(dup2(stdout2, STDOUT_FILENO),
153 "Restoring original STDOUT"); 153 "Restoring original STDOUT");
154 chk_zero(close(stdout2), "Closing temporary STDOUT"); 154 chk_zero(close(stdout2), "Closing temporary STDOUT");
155 } 155 }
156 156
157 chdir(buf); 157 chdir(buf);
158} 158}
159 159
160static void cgit_check_cache(struct cacheitem *item) 160static void cgit_check_cache(struct cacheitem *item)
161{ 161{
162 int i = 0; 162 int i = 0;
163 163
164 top: 164 top:
165 if (++i > cgit_max_lock_attempts) { 165 if (++i > cgit_max_lock_attempts) {
166 die("cgit_refresh_cache: unable to lock %s: %s", 166 die("cgit_refresh_cache: unable to lock %s: %s",
167 item->name, strerror(errno)); 167 item->name, strerror(errno));
168 } 168 }
169 if (!cache_exist(item)) { 169 if (!cache_exist(item)) {
170 if (!cache_lock(item)) { 170 if (!cache_lock(item)) {
171 sleep(1); 171 sleep(1);
172 goto top; 172 goto top;
173 } 173 }
174 if (!cache_exist(item)) { 174 if (!cache_exist(item)) {
175 cgit_fill_cache(item, 1); 175 cgit_fill_cache(item, 1);
176 cache_unlock(item); 176 cache_unlock(item);
177 } else { 177 } else {
178 cache_cancel_lock(item); 178 cache_cancel_lock(item);
179 } 179 }
180 } else if (cache_expired(item) && cache_lock(item)) { 180 } else if (cache_expired(item) && cache_lock(item)) {
181 if (cache_expired(item)) { 181 if (cache_expired(item)) {
182 cgit_fill_cache(item, 1); 182 cgit_fill_cache(item, 1);
183 cache_unlock(item); 183 cache_unlock(item);
184 } else { 184 } else {
185 cache_cancel_lock(item); 185 cache_cancel_lock(item);
186 } 186 }
187 } 187 }
188} 188}
189 189
190static void cgit_print_cache(struct cacheitem *item) 190static void cgit_print_cache(struct cacheitem *item)
191{ 191{
192 static char buf[4096]; 192 static char buf[4096];
193 ssize_t i; 193 ssize_t i;
194 194
195 int fd = open(item->name, O_RDONLY); 195 int fd = open(item->name, O_RDONLY);
196 if (fd<0) 196 if (fd<0)
197 die("Unable to open cached file %s", item->name); 197 die("Unable to open cached file %s", item->name);
198 198
199 while((i=read(fd, buf, sizeof(buf))) > 0) 199 while((i=read(fd, buf, sizeof(buf))) > 0)
200 write(STDOUT_FILENO, buf, i); 200 write(STDOUT_FILENO, buf, i);
201 201
202 close(fd); 202 close(fd);
203} 203}
204 204
205static void cgit_parse_args(int argc, const char **argv) 205static void cgit_parse_args(int argc, const char **argv)
206{ 206{
207 int i; 207 int i;
208 208
209 for (i = 1; i < argc; i++) { 209 for (i = 1; i < argc; i++) {
210 if (!strncmp(argv[i], "--cache=", 8)) { 210 if (!strncmp(argv[i], "--cache=", 8)) {
211 cgit_cache_root = xstrdup(argv[i]+8); 211 cgit_cache_root = xstrdup(argv[i]+8);
212 } 212 }
213 if (!strcmp(argv[i], "--nocache")) { 213 if (!strcmp(argv[i], "--nocache")) {
214 cgit_nocache = 1; 214 cgit_nocache = 1;
215 } 215 }
216 if (!strncmp(argv[i], "--query=", 8)) { 216 if (!strncmp(argv[i], "--query=", 8)) {
217 cgit_querystring = xstrdup(argv[i]+8); 217 cgit_querystring = xstrdup(argv[i]+8);
218 } 218 }
219 if (!strncmp(argv[i], "--repo=", 7)) { 219 if (!strncmp(argv[i], "--repo=", 7)) {
220 cgit_query_repo = xstrdup(argv[i]+7); 220 cgit_query_repo = xstrdup(argv[i]+7);
221 } 221 }
222 if (!strncmp(argv[i], "--page=", 7)) { 222 if (!strncmp(argv[i], "--page=", 7)) {
223 cgit_query_page = xstrdup(argv[i]+7); 223 cgit_query_page = xstrdup(argv[i]+7);
224 } 224 }
225 if (!strncmp(argv[i], "--head=", 7)) { 225 if (!strncmp(argv[i], "--head=", 7)) {
226 cgit_query_head = xstrdup(argv[i]+7); 226 cgit_query_head = xstrdup(argv[i]+7);
227 cgit_query_has_symref = 1; 227 cgit_query_has_symref = 1;
228 } 228 }
229 if (!strncmp(argv[i], "--sha1=", 7)) { 229 if (!strncmp(argv[i], "--sha1=", 7)) {
230 cgit_query_sha1 = xstrdup(argv[i]+7); 230 cgit_query_sha1 = xstrdup(argv[i]+7);
231 cgit_query_has_sha1 = 1; 231 cgit_query_has_sha1 = 1;
232 } 232 }
233 if (!strncmp(argv[i], "--ofs=", 6)) { 233 if (!strncmp(argv[i], "--ofs=", 6)) {
234 cgit_query_ofs = atoi(argv[i]+6); 234 cgit_query_ofs = atoi(argv[i]+6);
235 } 235 }
236 } 236 }
237} 237}
238 238
239int main(int argc, const char **argv) 239int main(int argc, const char **argv)
240{ 240{
241 struct cacheitem item; 241 struct cacheitem item;
242 242
243 htmlfd = STDOUT_FILENO; 243 htmlfd = STDOUT_FILENO;
244 item.st.st_mtime = time(NULL); 244 item.st.st_mtime = time(NULL);
245 cgit_repolist.length = 0; 245 cgit_repolist.length = 0;
246 cgit_repolist.count = 0; 246 cgit_repolist.count = 0;
247 cgit_repolist.repos = NULL; 247 cgit_repolist.repos = NULL;
248 248
249 cgit_read_config(CGIT_CONFIG, cgit_global_config_cb); 249 cgit_read_config(CGIT_CONFIG, cgit_global_config_cb);
250 if (getenv("SCRIPT_NAME")) 250 if (getenv("SCRIPT_NAME"))
251 cgit_script_name = xstrdup(getenv("SCRIPT_NAME")); 251 cgit_script_name = xstrdup(getenv("SCRIPT_NAME"));
252 if (getenv("QUERY_STRING")) 252 if (getenv("QUERY_STRING"))
253 cgit_querystring = xstrdup(getenv("QUERY_STRING")); 253 cgit_querystring = xstrdup(getenv("QUERY_STRING"));
254 cgit_parse_args(argc, argv); 254 cgit_parse_args(argc, argv);
255 cgit_parse_query(cgit_querystring, cgit_querystring_cb); 255 cgit_parse_query(cgit_querystring, cgit_querystring_cb);
256 if (!cgit_prepare_cache(&item)) 256 if (!cgit_prepare_cache(&item))
257 return 0; 257 return 0;
258 if (cgit_nocache) { 258 if (cgit_nocache) {
259 cgit_fill_cache(&item, 0); 259 cgit_fill_cache(&item, 0);
260 } else { 260 } else {
261 cgit_check_cache(&item); 261 cgit_check_cache(&item);
262 cgit_print_cache(&item); 262 cgit_print_cache(&item);
263 } 263 }
264 return 0; 264 return 0;
265} 265}
diff --git a/ui-commit.c b/ui-commit.c
index 8011dfc..93eb8fd 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -8,229 +8,229 @@
8 8
9#include "cgit.h" 9#include "cgit.h"
10 10
11static int files, slots; 11static int files, slots;
12static int total_adds, total_rems, max_changes; 12static int total_adds, total_rems, max_changes;
13static int lines_added, lines_removed; 13static int lines_added, lines_removed;
14 14
15static struct fileinfo { 15static struct fileinfo {
16 char status; 16 char status;
17 unsigned char old_sha1[20]; 17 unsigned char old_sha1[20];
18 unsigned char new_sha1[20]; 18 unsigned char new_sha1[20];
19 unsigned short old_mode; 19 unsigned short old_mode;
20 unsigned short new_mode; 20 unsigned short new_mode;
21 char *old_path; 21 char *old_path;
22 char *new_path; 22 char *new_path;
23 unsigned int added; 23 unsigned int added;
24 unsigned int removed; 24 unsigned int removed;
25} *items; 25} *items;
26 26
27 27
28void print_fileinfo(struct fileinfo *info) 28void print_fileinfo(struct fileinfo *info)
29{ 29{
30 char *query, *query2; 30 char *query, *query2;
31 char *class; 31 char *class;
32 32
33 switch (info->status) { 33 switch (info->status) {
34 case DIFF_STATUS_ADDED: 34 case DIFF_STATUS_ADDED:
35 class = "add"; 35 class = "add";
36 break; 36 break;
37 case DIFF_STATUS_COPIED: 37 case DIFF_STATUS_COPIED:
38 class = "cpy"; 38 class = "cpy";
39 break; 39 break;
40 case DIFF_STATUS_DELETED: 40 case DIFF_STATUS_DELETED:
41 class = "del"; 41 class = "del";
42 break; 42 break;
43 case DIFF_STATUS_MODIFIED: 43 case DIFF_STATUS_MODIFIED:
44 class = "upd"; 44 class = "upd";
45 break; 45 break;
46 case DIFF_STATUS_RENAMED: 46 case DIFF_STATUS_RENAMED:
47 class = "mov"; 47 class = "mov";
48 break; 48 break;
49 case DIFF_STATUS_TYPE_CHANGED: 49 case DIFF_STATUS_TYPE_CHANGED:
50 class = "typ"; 50 class = "typ";
51 break; 51 break;
52 case DIFF_STATUS_UNKNOWN: 52 case DIFF_STATUS_UNKNOWN:
53 class = "unk"; 53 class = "unk";
54 break; 54 break;
55 case DIFF_STATUS_UNMERGED: 55 case DIFF_STATUS_UNMERGED:
56 class = "stg"; 56 class = "stg";
57 break; 57 break;
58 default: 58 default:
59 die("bug: unhandled diff status %c", info->status); 59 die("bug: unhandled diff status %c", info->status);
60 } 60 }
61 61
62 html("<tr>"); 62 html("<tr>");
63 htmlf("<td class='mode'>"); 63 htmlf("<td class='mode'>");
64 if (is_null_sha1(info->new_sha1)) { 64 if (is_null_sha1(info->new_sha1)) {
65 html_filemode(info->old_mode); 65 html_filemode(info->old_mode);
66 } else { 66 } else {
67 html_filemode(info->new_mode); 67 html_filemode(info->new_mode);
68 } 68 }
69 69
70 if (info->old_mode != info->new_mode && 70 if (info->old_mode != info->new_mode &&
71 !is_null_sha1(info->old_sha1) && 71 !is_null_sha1(info->old_sha1) &&
72 !is_null_sha1(info->new_sha1)) { 72 !is_null_sha1(info->new_sha1)) {
73 html("<span class='modechange'>["); 73 html("<span class='modechange'>[");
74 html_filemode(info->old_mode); 74 html_filemode(info->old_mode);
75 html("]</span>"); 75 html("]</span>");
76 } 76 }
77 htmlf("</td><td class='%s'>", class); 77 htmlf("</td><td class='%s'>", class);
78 query = fmt("id=%s&id2=%s&path=%s", sha1_to_hex(info->old_sha1), 78 query = fmt("id=%s&id2=%s&path=%s", sha1_to_hex(info->old_sha1),
79 sha1_to_hex(info->new_sha1), info->new_path); 79 sha1_to_hex(info->new_sha1), info->new_path);
80 html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), 80 html_link_open(cgit_pageurl(cgit_query_repo, "diff", query),
81 NULL, NULL); 81 NULL, NULL);
82 if (info->status == DIFF_STATUS_COPIED || 82 if (info->status == DIFF_STATUS_COPIED ||
83 info->status == DIFF_STATUS_RENAMED) { 83 info->status == DIFF_STATUS_RENAMED) {
84 html_txt(info->new_path); 84 html_txt(info->new_path);
85 htmlf("</a> (%s from ", info->status == DIFF_STATUS_COPIED ? 85 htmlf("</a> (%s from ", info->status == DIFF_STATUS_COPIED ?
86 "copied" : "renamed"); 86 "copied" : "renamed");
87 query2 = fmt("id=%s", sha1_to_hex(info->old_sha1)); 87 query2 = fmt("id=%s", sha1_to_hex(info->old_sha1));
88 html_link_open(cgit_pageurl(cgit_query_repo, "view", query2), 88 html_link_open(cgit_pageurl(cgit_query_repo, "view", query2),
89 NULL, NULL); 89 NULL, NULL);
90 html_txt(info->old_path); 90 html_txt(info->old_path);
91 html("</a>)"); 91 html("</a>)");
92 } else { 92 } else {
93 html_txt(info->new_path); 93 html_txt(info->new_path);
94 html("</a>"); 94 html("</a>");
95 } 95 }
96 html("</td><td class='right'>"); 96 html("</td><td class='right'>");
97 htmlf("%d", info->added + info->removed); 97 htmlf("%d", info->added + info->removed);
98 html("</td><td class='graph'>"); 98 html("</td><td class='graph'>");
99 htmlf("<table width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes)); 99 htmlf("<table width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes));
100 htmlf("<td class='add' style='width: %.1f%%;'/>", 100 htmlf("<td class='add' style='width: %.1f%%;'/>",
101 info->added * 100.0 / max_changes); 101 info->added * 100.0 / max_changes);
102 htmlf("<td class='rem' style='width: %.1f%%;'/>", 102 htmlf("<td class='rem' style='width: %.1f%%;'/>",
103 info->removed * 100.0 / max_changes); 103 info->removed * 100.0 / max_changes);
104 htmlf("<td class='none' style='width: %.1f%%;'/>", 104 htmlf("<td class='none' style='width: %.1f%%;'/>",
105 (max_changes - info->removed - info->added) * 100.0 / max_changes); 105 (max_changes - info->removed - info->added) * 100.0 / max_changes);
106 html("</tr></table></a></td></tr>\n"); 106 html("</tr></table></a></td></tr>\n");
107} 107}
108 108
109void cgit_count_diff_lines(char *line, int len) 109void cgit_count_diff_lines(char *line, int len)
110{ 110{
111 if (line && (len > 0)) { 111 if (line && (len > 0)) {
112 if (line[0] == '+') 112 if (line[0] == '+')
113 lines_added++; 113 lines_added++;
114 else if (line[0] == '-') 114 else if (line[0] == '-')
115 lines_removed++; 115 lines_removed++;
116 } 116 }
117} 117}
118 118
119void inspect_filepair(struct diff_filepair *pair) 119void inspect_filepair(struct diff_filepair *pair)
120{ 120{
121 files++; 121 files++;
122 lines_added = 0; 122 lines_added = 0;
123 lines_removed = 0; 123 lines_removed = 0;
124 cgit_diff_files(pair->one->sha1, pair->two->sha1, cgit_count_diff_lines); 124 cgit_diff_files(pair->one->sha1, pair->two->sha1, cgit_count_diff_lines);
125 if (files >= slots) { 125 if (files >= slots) {
126 if (slots == 0) 126 if (slots == 0)
127 slots = 4; 127 slots = 4;
128 else 128 else
129 slots = slots * 2; 129 slots = slots * 2;
130 items = xrealloc(items, slots * sizeof(struct fileinfo)); 130 items = xrealloc(items, slots * sizeof(struct fileinfo));
131 } 131 }
132 items[files-1].status = pair->status; 132 items[files-1].status = pair->status;
133 hashcpy(items[files-1].old_sha1, pair->one->sha1); 133 hashcpy(items[files-1].old_sha1, pair->one->sha1);
134 hashcpy(items[files-1].new_sha1, pair->two->sha1); 134 hashcpy(items[files-1].new_sha1, pair->two->sha1);
135 items[files-1].old_mode = pair->one->mode; 135 items[files-1].old_mode = pair->one->mode;
136 items[files-1].new_mode = pair->two->mode; 136 items[files-1].new_mode = pair->two->mode;
137 items[files-1].old_path = xstrdup(pair->one->path); 137 items[files-1].old_path = xstrdup(pair->one->path);
138 items[files-1].new_path = xstrdup(pair->two->path); 138 items[files-1].new_path = xstrdup(pair->two->path);
139 items[files-1].added = lines_added; 139 items[files-1].added = lines_added;
140 items[files-1].removed = lines_removed; 140 items[files-1].removed = lines_removed;
141 if (lines_added + lines_removed > max_changes) 141 if (lines_added + lines_removed > max_changes)
142 max_changes = lines_added + lines_removed; 142 max_changes = lines_added + lines_removed;
143 total_adds += lines_added; 143 total_adds += lines_added;
144 total_rems += lines_removed; 144 total_rems += lines_removed;
145} 145}
146 146
147 147
148void cgit_print_commit(const char *hex) 148void cgit_print_commit(const char *hex)
149{ 149{
150 struct commit *commit, *parent; 150 struct commit *commit, *parent;
151 struct commitinfo *info; 151 struct commitinfo *info;
152 struct commit_list *p; 152 struct commit_list *p;
153 unsigned char sha1[20]; 153 unsigned char sha1[20];
154 char *query; 154 char *query;
155 char *filename; 155 char *filename;
156 int i; 156 int i;
157 157
158 if (get_sha1(hex, sha1)) { 158 if (get_sha1(hex, sha1)) {
159 cgit_print_error(fmt("Bad object id: %s", hex)); 159 cgit_print_error(fmt("Bad object id: %s", hex));
160 return; 160 return;
161 } 161 }
162 commit = lookup_commit_reference(sha1); 162 commit = lookup_commit_reference(sha1);
163 if (!commit) { 163 if (!commit) {
164 cgit_print_error(fmt("Bad commit reference: %s", hex)); 164 cgit_print_error(fmt("Bad commit reference: %s", hex));
165 return; 165 return;
166 } 166 }
167 info = cgit_parse_commit(commit); 167 info = cgit_parse_commit(commit);
168 168
169 html("<table class='commit-info'>\n"); 169 html("<table class='commit-info'>\n");
170 html("<tr><th>author</th><td>"); 170 html("<tr><th>author</th><td>");
171 html_txt(info->author); 171 html_txt(info->author);
172 html(" "); 172 html(" ");
173 html_txt(info->author_email); 173 html_txt(info->author_email);
174 html("</td><td class='right'>"); 174 html("</td><td class='right'>");
175 cgit_print_date(info->author_date); 175 cgit_print_date(info->author_date);
176 html("</td></tr>\n"); 176 html("</td></tr>\n");
177 html("<tr><th>committer</th><td>"); 177 html("<tr><th>committer</th><td>");
178 html_txt(info->committer); 178 html_txt(info->committer);
179 html(" "); 179 html(" ");
180 html_txt(info->committer_email); 180 html_txt(info->committer_email);
181 html("</td><td class='right'>"); 181 html("</td><td class='right'>");
182 cgit_print_date(info->committer_date); 182 cgit_print_date(info->committer_date);
183 html("</td></tr>\n"); 183 html("</td></tr>\n");
184 html("<tr><th>tree</th><td colspan='2' class='sha1'><a href='"); 184 html("<tr><th>tree</th><td colspan='2' class='sha1'><a href='");
185 query = fmt("h=%s&id=%s", sha1_to_hex(commit->object.sha1), 185 query = fmt("h=%s&id=%s", sha1_to_hex(commit->object.sha1),
186 sha1_to_hex(commit->tree->object.sha1)); 186 sha1_to_hex(commit->tree->object.sha1));
187 html_attr(cgit_pageurl(cgit_query_repo, "tree", query)); 187 html_attr(cgit_pageurl(cgit_query_repo, "tree", query));
188 htmlf("'>%s</a></td></tr>\n", sha1_to_hex(commit->tree->object.sha1)); 188 htmlf("'>%s</a></td></tr>\n", sha1_to_hex(commit->tree->object.sha1));
189 for (p = commit->parents; p ; p = p->next) { 189 for (p = commit->parents; p ; p = p->next) {
190 parent = lookup_commit_reference(p->item->object.sha1); 190 parent = lookup_commit_reference(p->item->object.sha1);
191 if (!parent) { 191 if (!parent) {
192 html("<tr><td colspan='3'>"); 192 html("<tr><td colspan='3'>");
193 cgit_print_error("Error reading parent commit"); 193 cgit_print_error("Error reading parent commit");
194 html("</td></tr>"); 194 html("</td></tr>");
195 continue; 195 continue;
196 } 196 }
197 html("<tr><th>parent</th>" 197 html("<tr><th>parent</th>"
198 "<td colspan='2' class='sha1'>" 198 "<td colspan='2' class='sha1'>"
199 "<a href='"); 199 "<a href='");
200 query = fmt("id=%s", sha1_to_hex(p->item->object.sha1)); 200 query = fmt("h=%s", sha1_to_hex(p->item->object.sha1));
201 html_attr(cgit_pageurl(cgit_query_repo, "commit", query)); 201 html_attr(cgit_pageurl(cgit_query_repo, "commit", query));
202 htmlf("'>%s</a> (<a href='", 202 htmlf("'>%s</a> (<a href='",
203 sha1_to_hex(p->item->object.sha1)); 203 sha1_to_hex(p->item->object.sha1));
204 query = fmt("id=%s&id2=%s", sha1_to_hex(parent->tree->object.sha1), 204 query = fmt("id=%s&id2=%s", sha1_to_hex(parent->tree->object.sha1),
205 sha1_to_hex(commit->tree->object.sha1)); 205 sha1_to_hex(commit->tree->object.sha1));
206 html_attr(cgit_pageurl(cgit_query_repo, "diff", query)); 206 html_attr(cgit_pageurl(cgit_query_repo, "diff", query));
207 html("'>diff</a>)</td></tr>"); 207 html("'>diff</a>)</td></tr>");
208 } 208 }
209 if (cgit_repo->snapshots) { 209 if (cgit_repo->snapshots) {
210 htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='"); 210 htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='");
211 filename = fmt("%s-%s.zip", cgit_query_repo, hex); 211 filename = fmt("%s-%s.zip", cgit_query_repo, hex);
212 html_attr(cgit_pageurl(cgit_query_repo, "snapshot", 212 html_attr(cgit_pageurl(cgit_query_repo, "snapshot",
213 fmt("id=%s&name=%s", hex, filename))); 213 fmt("id=%s&name=%s", hex, filename)));
214 htmlf("'>%s</a></td></tr>", filename); 214 htmlf("'>%s</a></td></tr>", filename);
215 } 215 }
216 html("</table>\n"); 216 html("</table>\n");
217 html("<div class='commit-subject'>"); 217 html("<div class='commit-subject'>");
218 html_txt(info->subject); 218 html_txt(info->subject);
219 html("</div>"); 219 html("</div>");
220 html("<div class='commit-msg'>"); 220 html("<div class='commit-msg'>");
221 html_txt(info->msg); 221 html_txt(info->msg);
222 html("</div>"); 222 html("</div>");
223 if (!(commit->parents && commit->parents->next && commit->parents->next->next)) { 223 if (!(commit->parents && commit->parents->next && commit->parents->next->next)) {
224 html("<table class='diffstat'>"); 224 html("<table class='diffstat'>");
225 max_changes = 0; 225 max_changes = 0;
226 cgit_diff_commit(commit, inspect_filepair); 226 cgit_diff_commit(commit, inspect_filepair);
227 for(i = 0; i<files; i++) 227 for(i = 0; i<files; i++)
228 print_fileinfo(&items[i]); 228 print_fileinfo(&items[i]);
229 html("</table>"); 229 html("</table>");
230 html("<div class='diffstat-summary'>"); 230 html("<div class='diffstat-summary'>");
231 htmlf("%d files changed, %d insertions, %d deletions\n", 231 htmlf("%d files changed, %d insertions, %d deletions\n",
232 files, total_adds, total_rems); 232 files, total_adds, total_rems);
233 html("</div>"); 233 html("</div>");
234 } 234 }
235 cgit_free_commitinfo(info); 235 cgit_free_commitinfo(info);
236} 236}
diff --git a/ui-log.c b/ui-log.c
index 6d5509b..9d0ec02 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -1,124 +1,123 @@
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 cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines);
23} 23}
24 24
25void print_commit(struct commit *commit) 25void print_commit(struct commit *commit)
26{ 26{
27 char buf[32]; 27 char buf[32];
28 struct commitinfo *info; 28 struct commitinfo *info;
29 struct tm *time; 29 struct tm *time;
30 30
31 info = cgit_parse_commit(commit); 31 info = cgit_parse_commit(commit);
32 time = gmtime(&commit->date); 32 time = gmtime(&commit->date);
33 html("<tr><td>"); 33 html("<tr><td>");
34 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", time); 34 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", time);
35 html_txt(buf); 35 html_txt(buf);
36 html("</td><td>"); 36 html("</td><td>");
37 char *qry = fmt("id=%s", sha1_to_hex(commit->object.sha1)); 37 char *qry = fmt("h=%s", sha1_to_hex(commit->object.sha1));
38 char *url = cgit_pageurl(cgit_query_repo, "commit", qry); 38 char *url = cgit_pageurl(cgit_query_repo, "commit", qry);
39 html_link_open(url, NULL, NULL); 39 html_link_open(url, NULL, NULL);
40 html_ntxt(cgit_max_msg_len, info->subject); 40 html_ntxt(cgit_max_msg_len, info->subject);
41 html_link_close(); 41 html_link_close();
42 files = 0; 42 files = 0;
43 lines = 0; 43 lines = 0;
44 cgit_diff_commit(commit, inspect_files); 44 cgit_diff_commit(commit, inspect_files);
45 html("</td><td class='right'>"); 45 html("</td><td class='right'>");
46 htmlf("%d", files); 46 htmlf("%d", files);
47 html("</td><td class='right'>"); 47 html("</td><td class='right'>");
48 htmlf("%d", lines); 48 htmlf("%d", lines);
49 html("</td><td>"); 49 html("</td><td>");
50 html_txt(info->author); 50 html_txt(info->author);
51 html("</td></tr>\n"); 51 html("</td></tr>\n");
52 cgit_free_commitinfo(info); 52 cgit_free_commitinfo(info);
53} 53}
54 54
55 55
56void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path) 56void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path)
57{ 57{
58 struct rev_info rev; 58 struct rev_info rev;
59 struct commit *commit; 59 struct commit *commit;
60 const char *argv[] = {NULL, tip, NULL, NULL, NULL}; 60 const char *argv[] = {NULL, tip, NULL, NULL, NULL};
61 int argc = 2; 61 int argc = 2;
62 int i; 62 int i;
63 63
64 if (grep) 64 if (grep)
65 argv[argc++] = fmt("--grep=%s", grep); 65 argv[argc++] = fmt("--grep=%s", grep);
66 if (path) { 66 if (path) {
67 argv[argc++] = "--"; 67 argv[argc++] = "--";
68 argv[argc++] = path; 68 argv[argc++] = path;
69 } 69 }
70 init_revisions(&rev, NULL); 70 init_revisions(&rev, NULL);
71 rev.abbrev = DEFAULT_ABBREV; 71 rev.abbrev = DEFAULT_ABBREV;
72 rev.commit_format = CMIT_FMT_DEFAULT; 72 rev.commit_format = CMIT_FMT_DEFAULT;
73 rev.verbose_header = 1; 73 rev.verbose_header = 1;
74 rev.show_root_diff = 0; 74 rev.show_root_diff = 0;
75 setup_revisions(argc, argv, &rev, NULL); 75 setup_revisions(argc, argv, &rev, NULL);
76 if (rev.grep_filter) { 76 if (rev.grep_filter) {
77 rev.grep_filter->regflags |= REG_ICASE; 77 rev.grep_filter->regflags |= REG_ICASE;
78 compile_grep_patterns(rev.grep_filter); 78 compile_grep_patterns(rev.grep_filter);
79 } 79 }
80 prepare_revision_walk(&rev); 80 prepare_revision_walk(&rev);
81 81
82 html("<table class='list nowrap'>"); 82 html("<table class='list nowrap'>");
83 html("<tr class='nohover'><th class='left'>Date</th>" 83 html("<tr class='nohover'><th class='left'>Date</th>"
84 "<th class='left'>Message</th>" 84 "<th class='left'>Message</th>"
85 "<th class='left'>Files</th>" 85 "<th class='left'>Files</th>"
86 "<th class='left'>Lines</th>" 86 "<th class='left'>Lines</th>"
87 "<th class='left'>Author</th></tr>\n"); 87 "<th class='left'>Author</th></tr>\n");
88 88
89 if (ofs<0) 89 if (ofs<0)
90 ofs = 0; 90 ofs = 0;
91 91
92 for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) { 92 for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) {
93 free(commit->buffer); 93 free(commit->buffer);
94 commit->buffer = NULL; 94 commit->buffer = NULL;
95 free_commit_list(commit->parents); 95 free_commit_list(commit->parents);
96 commit->parents = NULL; 96 commit->parents = NULL;
97 } 97 }
98 98
99 for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) { 99 for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) {
100 print_commit(commit); 100 print_commit(commit);
101 free(commit->buffer); 101 free(commit->buffer);
102 commit->buffer = NULL; 102 commit->buffer = NULL;
103 free_commit_list(commit->parents); 103 free_commit_list(commit->parents);
104 commit->parents = NULL; 104 commit->parents = NULL;
105 } 105 }
106 html("</table>\n"); 106 html("</table>\n");
107 107
108 html("<div class='pager'>"); 108 html("<div class='pager'>");
109 if (ofs > 0) { 109 if (ofs > 0) {
110 html("&nbsp;<a href='"); 110 html("&nbsp;<a href='");
111 html(cgit_pageurl(cgit_query_repo, cgit_query_page, 111 html(cgit_pageurl(cgit_query_repo, cgit_query_page,
112 fmt("h=%s&ofs=%d", tip, ofs-cnt))); 112 fmt("h=%s&ofs=%d", tip, ofs-cnt)));
113 html("'>[prev]</a>&nbsp;"); 113 html("'>[prev]</a>&nbsp;");
114 } 114 }
115 115
116 if ((commit = get_revision(&rev)) != NULL) { 116 if ((commit = get_revision(&rev)) != NULL) {
117 html("&nbsp;<a href='"); 117 html("&nbsp;<a href='");
118 html(cgit_pageurl(cgit_query_repo, "log", 118 html(cgit_pageurl(cgit_query_repo, "log",
119 fmt("h=%s&ofs=%d", tip, ofs+cnt))); 119 fmt("h=%s&ofs=%d", tip, ofs+cnt)));
120 html("'>[next]</a>&nbsp;"); 120 html("'>[next]</a>&nbsp;");
121 } 121 }
122 html("</div>"); 122 html("</div>");
123} 123}
124
diff --git a/ui-summary.c b/ui-summary.c
index b99ea98..e7158cc 100644
--- a/ui-summary.c
+++ b/ui-summary.c
@@ -1,206 +1,210 @@
1/* ui-summary.c: functions for generating repo summary page 1/* ui-summary.c: functions for generating repo summary page
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
11static int header; 11static int header;
12 12
13static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1, 13static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1,
14 int flags, void *cb_data) 14 int flags, void *cb_data)
15{ 15{
16 struct commit *commit; 16 struct commit *commit;
17 struct commitinfo *info; 17 struct commitinfo *info;
18 char buf[256], *url; 18 char buf[256], *url;
19 19
20 strncpy(buf, refname, sizeof(buf)); 20 strncpy(buf, refname, sizeof(buf));
21 commit = lookup_commit(sha1); 21 commit = lookup_commit(sha1);
22 if (commit && !parse_commit(commit)){ 22 if (commit && !parse_commit(commit)){
23 info = cgit_parse_commit(commit); 23 info = cgit_parse_commit(commit);
24 html("<tr><td>"); 24 html("<tr><td>");
25 url = cgit_pageurl(cgit_query_repo, "log", 25 url = cgit_pageurl(cgit_query_repo, "log",
26 fmt("h=%s", refname)); 26 fmt("h=%s", refname));
27 html_link_open(url, NULL, NULL); 27 html_link_open(url, NULL, NULL);
28 html_txt(buf); 28 html_txt(buf);
29 html_link_close(); 29 html_link_close();
30 html("</td><td>"); 30 html("</td><td>");
31 cgit_print_date(commit->date); 31 cgit_print_date(commit->date);
32 html("</td><td>"); 32 html("</td><td>");
33 html_txt(info->author); 33 html_txt(info->author);
34 html("</td><td>"); 34 html("</td><td>");
35 url = cgit_pageurl(cgit_query_repo, "commit", 35 url = cgit_pageurl(cgit_query_repo, "commit",
36 fmt("id=%s", sha1_to_hex(sha1))); 36 fmt("h=%s", sha1_to_hex(sha1)));
37 html_link_open(url, NULL, NULL); 37 html_link_open(url, NULL, NULL);
38 html_ntxt(cgit_max_msg_len, info->subject); 38 html_ntxt(cgit_max_msg_len, info->subject);
39 html_link_close(); 39 html_link_close();
40 html("</td></tr>\n"); 40 html("</td></tr>\n");
41 cgit_free_commitinfo(info); 41 cgit_free_commitinfo(info);
42 } else { 42 } else {
43 html("<tr><td>"); 43 html("<tr><td>");
44 html_txt(buf); 44 html_txt(buf);
45 html("</td><td colspan='3'>"); 45 html("</td><td colspan='3'>");
46 htmlf("*** bad ref %s ***", sha1_to_hex(sha1)); 46 htmlf("*** bad ref %s ***", sha1_to_hex(sha1));
47 html("</td></tr>\n"); 47 html("</td></tr>\n");
48 } 48 }
49 return 0; 49 return 0;
50} 50}
51 51
52 52
53static void cgit_print_object_ref(struct object *obj) 53static void cgit_print_object_ref(struct object *obj)
54{ 54{
55 char *page, *url; 55 char *page, *arg, *url;
56 56
57 if (obj->type == OBJ_COMMIT) 57 if (obj->type == OBJ_COMMIT) {
58 page = "commit"; 58 page = "commit";
59 else if (obj->type == OBJ_TREE) 59 arg = "h";
60 } else if (obj->type == OBJ_TREE) {
60 page = "tree"; 61 page = "tree";
61 else 62 arg = "id";
63 } else {
62 page = "view"; 64 page = "view";
65 arg = "id";
66 }
63 67
64 url = cgit_pageurl(cgit_query_repo, page, 68 url = cgit_pageurl(cgit_query_repo, page,
65 fmt("id=%s", sha1_to_hex(obj->sha1))); 69 fmt("%s=%s", arg, sha1_to_hex(obj->sha1)));
66 html_link_open(url, NULL, NULL); 70 html_link_open(url, NULL, NULL);
67 htmlf("%s %s", typename(obj->type), 71 htmlf("%s %s", typename(obj->type),
68 sha1_to_hex(obj->sha1)); 72 sha1_to_hex(obj->sha1));
69 html_link_close(); 73 html_link_close();
70} 74}
71 75
72static void print_tag_header() 76static void print_tag_header()
73{ 77{
74 html("<tr class='nohover'><th class='left'>Tag</th>" 78 html("<tr class='nohover'><th class='left'>Tag</th>"
75 "<th class='left'>Created</th>" 79 "<th class='left'>Created</th>"
76 "<th class='left'>Author</th>" 80 "<th class='left'>Author</th>"
77 "<th class='left'>Reference</th></tr>\n"); 81 "<th class='left'>Reference</th></tr>\n");
78 header = 1; 82 header = 1;
79} 83}
80 84
81static int cgit_print_tag_cb(const char *refname, const unsigned char *sha1, 85static int cgit_print_tag_cb(const char *refname, const unsigned char *sha1,
82 int flags, void *cb_data) 86 int flags, void *cb_data)
83{ 87{
84 struct tag *tag; 88 struct tag *tag;
85 struct taginfo *info; 89 struct taginfo *info;
86 struct object *obj; 90 struct object *obj;
87 char buf[256], *url; 91 char buf[256], *url;
88 92
89 strncpy(buf, refname, sizeof(buf)); 93 strncpy(buf, refname, sizeof(buf));
90 obj = parse_object(sha1); 94 obj = parse_object(sha1);
91 if (!obj) 95 if (!obj)
92 return 1; 96 return 1;
93 if (obj->type == OBJ_TAG) { 97 if (obj->type == OBJ_TAG) {
94 tag = lookup_tag(sha1); 98 tag = lookup_tag(sha1);
95 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 99 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
96 return 2; 100 return 2;
97 if (!header) 101 if (!header)
98 print_tag_header(); 102 print_tag_header();
99 html("<tr><td>"); 103 html("<tr><td>");
100 url = cgit_pageurl(cgit_query_repo, "view", 104 url = cgit_pageurl(cgit_query_repo, "view",
101 fmt("id=%s", sha1_to_hex(sha1))); 105 fmt("id=%s", sha1_to_hex(sha1)));
102 html_link_open(url, NULL, NULL); 106 html_link_open(url, NULL, NULL);
103 html_txt(buf); 107 html_txt(buf);
104 html_link_close(); 108 html_link_close();
105 html("</td><td>"); 109 html("</td><td>");
106 if (info->tagger_date > 0) 110 if (info->tagger_date > 0)
107 cgit_print_date(info->tagger_date); 111 cgit_print_date(info->tagger_date);
108 html("</td><td>"); 112 html("</td><td>");
109 if (info->tagger) 113 if (info->tagger)
110 html(info->tagger); 114 html(info->tagger);
111 html("</td><td>"); 115 html("</td><td>");
112 cgit_print_object_ref(tag->tagged); 116 cgit_print_object_ref(tag->tagged);
113 html("</td></tr>\n"); 117 html("</td></tr>\n");
114 } else { 118 } else {
115 if (!header) 119 if (!header)
116 print_tag_header(); 120 print_tag_header();
117 html("<tr><td>"); 121 html("<tr><td>");
118 html_txt(buf); 122 html_txt(buf);
119 html("</td><td colspan='2'/><td>"); 123 html("</td><td colspan='2'/><td>");
120 cgit_print_object_ref(obj); 124 cgit_print_object_ref(obj);
121 html("</td></tr>\n"); 125 html("</td></tr>\n");
122 } 126 }
123 return 0; 127 return 0;
124} 128}
125 129
126static int cgit_print_archive_cb(const char *refname, const unsigned char *sha1, 130static int cgit_print_archive_cb(const char *refname, const unsigned char *sha1,
127 int flags, void *cb_data) 131 int flags, void *cb_data)
128{ 132{
129 struct tag *tag; 133 struct tag *tag;
130 struct taginfo *info; 134 struct taginfo *info;
131 struct object *obj; 135 struct object *obj;
132 char buf[256], *url; 136 char buf[256], *url;
133 unsigned char fileid[20]; 137 unsigned char fileid[20];
134 138
135 if (prefixcmp(refname, "refs/archives")) 139 if (prefixcmp(refname, "refs/archives"))
136 return 0; 140 return 0;
137 strncpy(buf, refname+14, sizeof(buf)); 141 strncpy(buf, refname+14, sizeof(buf));
138 obj = parse_object(sha1); 142 obj = parse_object(sha1);
139 if (!obj) 143 if (!obj)
140 return 1; 144 return 1;
141 if (obj->type == OBJ_TAG) { 145 if (obj->type == OBJ_TAG) {
142 tag = lookup_tag(sha1); 146 tag = lookup_tag(sha1);
143 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 147 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
144 return 0; 148 return 0;
145 hashcpy(fileid, tag->tagged->sha1); 149 hashcpy(fileid, tag->tagged->sha1);
146 } else if (obj->type != OBJ_BLOB) { 150 } else if (obj->type != OBJ_BLOB) {
147 return 0; 151 return 0;
148 } else { 152 } else {
149 hashcpy(fileid, sha1); 153 hashcpy(fileid, sha1);
150 } 154 }
151 if (!header) { 155 if (!header) {
152 html("<table>"); 156 html("<table>");
153 html("<tr><th>Downloads</th></tr>"); 157 html("<tr><th>Downloads</th></tr>");
154 header = 1; 158 header = 1;
155 } 159 }
156 html("<tr><td>"); 160 html("<tr><td>");
157 url = cgit_pageurl(cgit_query_repo, "blob", 161 url = cgit_pageurl(cgit_query_repo, "blob",
158 fmt("id=%s&path=%s", sha1_to_hex(fileid), 162 fmt("id=%s&path=%s", sha1_to_hex(fileid),
159 buf)); 163 buf));
160 html_link_open(url, NULL, NULL); 164 html_link_open(url, NULL, NULL);
161 html_txt(buf); 165 html_txt(buf);
162 html_link_close(); 166 html_link_close();
163 html("</td><tr>"); 167 html("</td><tr>");
164 return 0; 168 return 0;
165} 169}
166 170
167static void cgit_print_branches() 171static void cgit_print_branches()
168{ 172{
169 html("<tr class='nohover'><th class='left'>Branch</th>" 173 html("<tr class='nohover'><th class='left'>Branch</th>"
170 "<th class='left'>Updated</th>" 174 "<th class='left'>Updated</th>"
171 "<th class='left'>Author</th>" 175 "<th class='left'>Author</th>"
172 "<th class='left'>Head commit</th></tr>\n"); 176 "<th class='left'>Head commit</th></tr>\n");
173 for_each_branch_ref(cgit_print_branch_cb, NULL); 177 for_each_branch_ref(cgit_print_branch_cb, NULL);
174} 178}
175 179
176static void cgit_print_tags() 180static void cgit_print_tags()
177{ 181{
178 header = 0; 182 header = 0;
179 for_each_tag_ref(cgit_print_tag_cb, NULL); 183 for_each_tag_ref(cgit_print_tag_cb, NULL);
180} 184}
181 185
182static void cgit_print_archives() 186static void cgit_print_archives()
183{ 187{
184 header = 0; 188 header = 0;
185 for_each_ref(cgit_print_archive_cb, NULL); 189 for_each_ref(cgit_print_archive_cb, NULL);
186 if (header) 190 if (header)
187 html("</table>"); 191 html("</table>");
188} 192}
189 193
190void cgit_print_summary() 194void cgit_print_summary()
191{ 195{
192 html("<table class='list nowrap'>"); 196 html("<table class='list nowrap'>");
193 html("<tr class='nohover'><td id='summary' colspan='3'>"); 197 html("<tr class='nohover'><td id='summary' colspan='3'>");
194 html("<h2>"); 198 html("<h2>");
195 html_txt(cgit_repo->name); 199 html_txt(cgit_repo->name);
196 html(" - "); 200 html(" - ");
197 html_txt(cgit_repo->desc); 201 html_txt(cgit_repo->desc);
198 html("</h2>"); 202 html("</h2>");
199 html("</td><td id='archivelist'>"); 203 html("</td><td id='archivelist'>");
200 cgit_print_archives(); 204 cgit_print_archives();
201 html("</td></tr>"); 205 html("</td></tr>");
202 cgit_print_branches(); 206 cgit_print_branches();
203 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>"); 207 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>");
204 cgit_print_tags(); 208 cgit_print_tags();
205 html("</table>"); 209 html("</table>");
206} 210}