summaryrefslogtreecommitdiffabout
path: root/ui-shared.c
authorLars Hjemli <hjemli@gmail.com>2008-08-06 09:07:13 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2008-08-06 09:21:30 (UTC)
commit65b7b876aaaf50fc15060533359d6561f4f1819a (patch) (unidiff)
treec5cfe73456cf31afb13bcb12c5331fa711f89d71 /ui-shared.c
parente5da4bca54574522b28f88cab0dc8ebad9e35a73 (diff)
downloadcgit-65b7b876aaaf50fc15060533359d6561f4f1819a.zip
cgit-65b7b876aaaf50fc15060533359d6561f4f1819a.tar.gz
cgit-65b7b876aaaf50fc15060533359d6561f4f1819a.tar.bz2
ui-tree: link to plain view instead of blob view
The urls for plain view makes it possible to download blobs without knowing their SHA1, but the function needs to be promoted and the link from tree view seems like a perfect fit. PS: Although hidden, the blob view still is nice for direct blob access so there's no point in removing it. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (limited to 'ui-shared.c') (more/less context) (ignore whitespace changes)
-rw-r--r--ui-shared.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/ui-shared.c b/ui-shared.c
index 4408969..a2e0dd2 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -1,501 +1,507 @@
1/* ui-shared.c: common web output functions 1/* ui-shared.c: common web output 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#include "cmd.h" 10#include "cmd.h"
11#include "html.h" 11#include "html.h"
12 12
13const char cgit_doctype[] = 13const char cgit_doctype[] =
14"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" 14"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
15" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"; 15" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
16 16
17static char *http_date(time_t t) 17static char *http_date(time_t t)
18{ 18{
19 static char day[][4] = 19 static char day[][4] =
20 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 20 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
21 static char month[][4] = 21 static char month[][4] =
22 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 22 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
23 "Jul", "Aug", "Sep", "Oct", "Now", "Dec"}; 23 "Jul", "Aug", "Sep", "Oct", "Now", "Dec"};
24 struct tm *tm = gmtime(&t); 24 struct tm *tm = gmtime(&t);
25 return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday], 25 return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday],
26 tm->tm_mday, month[tm->tm_mon], 1900+tm->tm_year, 26 tm->tm_mday, month[tm->tm_mon], 1900+tm->tm_year,
27 tm->tm_hour, tm->tm_min, tm->tm_sec); 27 tm->tm_hour, tm->tm_min, tm->tm_sec);
28} 28}
29 29
30void cgit_print_error(char *msg) 30void cgit_print_error(char *msg)
31{ 31{
32 html("<div class='error'>"); 32 html("<div class='error'>");
33 html_txt(msg); 33 html_txt(msg);
34 html("</div>\n"); 34 html("</div>\n");
35} 35}
36 36
37char *cgit_rooturl() 37char *cgit_rooturl()
38{ 38{
39 if (ctx.cfg.virtual_root) 39 if (ctx.cfg.virtual_root)
40 return fmt("%s/", ctx.cfg.virtual_root); 40 return fmt("%s/", ctx.cfg.virtual_root);
41 else 41 else
42 return ctx.cfg.script_name; 42 return ctx.cfg.script_name;
43} 43}
44 44
45char *cgit_repourl(const char *reponame) 45char *cgit_repourl(const char *reponame)
46{ 46{
47 if (ctx.cfg.virtual_root) { 47 if (ctx.cfg.virtual_root) {
48 return fmt("%s/%s/", ctx.cfg.virtual_root, reponame); 48 return fmt("%s/%s/", ctx.cfg.virtual_root, reponame);
49 } else { 49 } else {
50 return fmt("?r=%s", reponame); 50 return fmt("?r=%s", reponame);
51 } 51 }
52} 52}
53 53
54char *cgit_fileurl(const char *reponame, const char *pagename, 54char *cgit_fileurl(const char *reponame, const char *pagename,
55 const char *filename, const char *query) 55 const char *filename, const char *query)
56{ 56{
57 char *tmp; 57 char *tmp;
58 char *delim; 58 char *delim;
59 59
60 if (ctx.cfg.virtual_root) { 60 if (ctx.cfg.virtual_root) {
61 tmp = fmt("%s/%s/%s/%s", ctx.cfg.virtual_root, reponame, 61 tmp = fmt("%s/%s/%s/%s", ctx.cfg.virtual_root, reponame,
62 pagename, (filename ? filename:"")); 62 pagename, (filename ? filename:""));
63 delim = "?"; 63 delim = "?";
64 } else { 64 } else {
65 tmp = fmt("?url=%s/%s/%s", reponame, pagename, 65 tmp = fmt("?url=%s/%s/%s", reponame, pagename,
66 (filename ? filename : "")); 66 (filename ? filename : ""));
67 delim = "&"; 67 delim = "&";
68 } 68 }
69 if (query) 69 if (query)
70 tmp = fmt("%s%s%s", tmp, delim, query); 70 tmp = fmt("%s%s%s", tmp, delim, query);
71 return tmp; 71 return tmp;
72} 72}
73 73
74char *cgit_pageurl(const char *reponame, const char *pagename, 74char *cgit_pageurl(const char *reponame, const char *pagename,
75 const char *query) 75 const char *query)
76{ 76{
77 return cgit_fileurl(reponame,pagename,0,query); 77 return cgit_fileurl(reponame,pagename,0,query);
78} 78}
79 79
80const char *cgit_repobasename(const char *reponame) 80const char *cgit_repobasename(const char *reponame)
81{ 81{
82 /* I assume we don't need to store more than one repo basename */ 82 /* I assume we don't need to store more than one repo basename */
83 static char rvbuf[1024]; 83 static char rvbuf[1024];
84 int p; 84 int p;
85 const char *rv; 85 const char *rv;
86 strncpy(rvbuf,reponame,sizeof(rvbuf)); 86 strncpy(rvbuf,reponame,sizeof(rvbuf));
87 if(rvbuf[sizeof(rvbuf)-1]) 87 if(rvbuf[sizeof(rvbuf)-1])
88 die("cgit_repobasename: truncated repository name '%s'", reponame); 88 die("cgit_repobasename: truncated repository name '%s'", reponame);
89 p = strlen(rvbuf)-1; 89 p = strlen(rvbuf)-1;
90 /* strip trailing slashes */ 90 /* strip trailing slashes */
91 while(p && rvbuf[p]=='/') rvbuf[p--]=0; 91 while(p && rvbuf[p]=='/') rvbuf[p--]=0;
92 /* strip trailing .git */ 92 /* strip trailing .git */
93 if(p>=3 && !strncmp(&rvbuf[p-3],".git",4)) { 93 if(p>=3 && !strncmp(&rvbuf[p-3],".git",4)) {
94 p -= 3; rvbuf[p--] = 0; 94 p -= 3; rvbuf[p--] = 0;
95 } 95 }
96 /* strip more trailing slashes if any */ 96 /* strip more trailing slashes if any */
97 while( p && rvbuf[p]=='/') rvbuf[p--]=0; 97 while( p && rvbuf[p]=='/') rvbuf[p--]=0;
98 /* find last slash in the remaining string */ 98 /* find last slash in the remaining string */
99 rv = strrchr(rvbuf,'/'); 99 rv = strrchr(rvbuf,'/');
100 if(rv) 100 if(rv)
101 return ++rv; 101 return ++rv;
102 return rvbuf; 102 return rvbuf;
103} 103}
104 104
105char *cgit_currurl() 105char *cgit_currurl()
106{ 106{
107 if (!ctx.cfg.virtual_root) 107 if (!ctx.cfg.virtual_root)
108 return ctx.cfg.script_name; 108 return ctx.cfg.script_name;
109 else if (ctx.qry.page) 109 else if (ctx.qry.page)
110 return fmt("%s/%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo, ctx.qry.page); 110 return fmt("%s/%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo, ctx.qry.page);
111 else if (ctx.qry.repo) 111 else if (ctx.qry.repo)
112 return fmt("%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo); 112 return fmt("%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo);
113 else 113 else
114 return fmt("%s/", ctx.cfg.virtual_root); 114 return fmt("%s/", ctx.cfg.virtual_root);
115} 115}
116 116
117static void site_url(char *page, char *search, int ofs) 117static void site_url(char *page, char *search, int ofs)
118{ 118{
119 char *delim = "?"; 119 char *delim = "?";
120 120
121 if (ctx.cfg.virtual_root) { 121 if (ctx.cfg.virtual_root) {
122 html_attr(ctx.cfg.virtual_root); 122 html_attr(ctx.cfg.virtual_root);
123 if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/') 123 if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/')
124 html("/"); 124 html("/");
125 } else 125 } else
126 html(ctx.cfg.script_name); 126 html(ctx.cfg.script_name);
127 127
128 if (page) { 128 if (page) {
129 htmlf("?p=%s", page); 129 htmlf("?p=%s", page);
130 delim = "&"; 130 delim = "&";
131 } 131 }
132 if (search) { 132 if (search) {
133 html(delim); 133 html(delim);
134 html("q="); 134 html("q=");
135 html_attr(search); 135 html_attr(search);
136 delim = "&"; 136 delim = "&";
137 } 137 }
138 if (ofs) { 138 if (ofs) {
139 html(delim); 139 html(delim);
140 htmlf("ofs=%d", ofs); 140 htmlf("ofs=%d", ofs);
141 } 141 }
142} 142}
143 143
144static void site_link(char *page, char *name, char *title, char *class, 144static void site_link(char *page, char *name, char *title, char *class,
145 char *search, int ofs) 145 char *search, int ofs)
146{ 146{
147 html("<a"); 147 html("<a");
148 if (title) { 148 if (title) {
149 html(" title='"); 149 html(" title='");
150 html_attr(title); 150 html_attr(title);
151 html("'"); 151 html("'");
152 } 152 }
153 if (class) { 153 if (class) {
154 html(" class='"); 154 html(" class='");
155 html_attr(class); 155 html_attr(class);
156 html("'"); 156 html("'");
157 } 157 }
158 html(" href='"); 158 html(" href='");
159 site_url(page, search, ofs); 159 site_url(page, search, ofs);
160 html("'>"); 160 html("'>");
161 html_txt(name); 161 html_txt(name);
162 html("</a>"); 162 html("</a>");
163} 163}
164 164
165void cgit_index_link(char *name, char *title, char *class, char *pattern, 165void cgit_index_link(char *name, char *title, char *class, char *pattern,
166 int ofs) 166 int ofs)
167{ 167{
168 site_link(NULL, name, title, class, pattern, ofs); 168 site_link(NULL, name, title, class, pattern, ofs);
169} 169}
170 170
171static char *repolink(char *title, char *class, char *page, char *head, 171static char *repolink(char *title, char *class, char *page, char *head,
172 char *path) 172 char *path)
173{ 173{
174 char *delim = "?"; 174 char *delim = "?";
175 175
176 html("<a"); 176 html("<a");
177 if (title) { 177 if (title) {
178 html(" title='"); 178 html(" title='");
179 html_attr(title); 179 html_attr(title);
180 html("'"); 180 html("'");
181 } 181 }
182 if (class) { 182 if (class) {
183 html(" class='"); 183 html(" class='");
184 html_attr(class); 184 html_attr(class);
185 html("'"); 185 html("'");
186 } 186 }
187 html(" href='"); 187 html(" href='");
188 if (ctx.cfg.virtual_root) { 188 if (ctx.cfg.virtual_root) {
189 html_attr(ctx.cfg.virtual_root); 189 html_attr(ctx.cfg.virtual_root);
190 if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/') 190 if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/')
191 html("/"); 191 html("/");
192 html_attr(ctx.repo->url); 192 html_attr(ctx.repo->url);
193 if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') 193 if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')
194 html("/"); 194 html("/");
195 if (page) { 195 if (page) {
196 html(page); 196 html(page);
197 html("/"); 197 html("/");
198 if (path) 198 if (path)
199 html_attr(path); 199 html_attr(path);
200 } 200 }
201 } else { 201 } else {
202 html(ctx.cfg.script_name); 202 html(ctx.cfg.script_name);
203 html("?url="); 203 html("?url=");
204 html_attr(ctx.repo->url); 204 html_attr(ctx.repo->url);
205 if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') 205 if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')
206 html("/"); 206 html("/");
207 if (page) { 207 if (page) {
208 html(page); 208 html(page);
209 html("/"); 209 html("/");
210 if (path) 210 if (path)
211 html_attr(path); 211 html_attr(path);
212 } 212 }
213 delim = "&amp;"; 213 delim = "&amp;";
214 } 214 }
215 if (head && strcmp(head, ctx.repo->defbranch)) { 215 if (head && strcmp(head, ctx.repo->defbranch)) {
216 html(delim); 216 html(delim);
217 html("h="); 217 html("h=");
218 html_attr(head); 218 html_attr(head);
219 delim = "&amp;"; 219 delim = "&amp;";
220 } 220 }
221 return fmt("%s", delim); 221 return fmt("%s", delim);
222} 222}
223 223
224static void reporevlink(char *page, char *name, char *title, char *class, 224static void reporevlink(char *page, char *name, char *title, char *class,
225 char *head, char *rev, char *path) 225 char *head, char *rev, char *path)
226{ 226{
227 char *delim; 227 char *delim;
228 228
229 delim = repolink(title, class, page, head, path); 229 delim = repolink(title, class, page, head, path);
230 if (rev && strcmp(rev, ctx.qry.head)) { 230 if (rev && strcmp(rev, ctx.qry.head)) {
231 html(delim); 231 html(delim);
232 html("id="); 232 html("id=");
233 html_attr(rev); 233 html_attr(rev);
234 } 234 }
235 html("'>"); 235 html("'>");
236 html_txt(name); 236 html_txt(name);
237 html("</a>"); 237 html("</a>");
238} 238}
239 239
240void cgit_tree_link(char *name, char *title, char *class, char *head, 240void cgit_tree_link(char *name, char *title, char *class, char *head,
241 char *rev, char *path) 241 char *rev, char *path)
242{ 242{
243 reporevlink("tree", name, title, class, head, rev, path); 243 reporevlink("tree", name, title, class, head, rev, path);
244} 244}
245 245
246void cgit_plain_link(char *name, char *title, char *class, char *head,
247 char *rev, char *path)
248{
249 reporevlink("plain", name, title, class, head, rev, path);
250}
251
246void cgit_log_link(char *name, char *title, char *class, char *head, 252void cgit_log_link(char *name, char *title, char *class, char *head,
247 char *rev, char *path, int ofs, char *grep, char *pattern) 253 char *rev, char *path, int ofs, char *grep, char *pattern)
248{ 254{
249 char *delim; 255 char *delim;
250 256
251 delim = repolink(title, class, "log", head, path); 257 delim = repolink(title, class, "log", head, path);
252 if (rev && strcmp(rev, ctx.qry.head)) { 258 if (rev && strcmp(rev, ctx.qry.head)) {
253 html(delim); 259 html(delim);
254 html("id="); 260 html("id=");
255 html_attr(rev); 261 html_attr(rev);
256 delim = "&"; 262 delim = "&";
257 } 263 }
258 if (grep && pattern) { 264 if (grep && pattern) {
259 html(delim); 265 html(delim);
260 html("qt="); 266 html("qt=");
261 html_attr(grep); 267 html_attr(grep);
262 delim = "&"; 268 delim = "&";
263 html(delim); 269 html(delim);
264 html("q="); 270 html("q=");
265 html_attr(pattern); 271 html_attr(pattern);
266 } 272 }
267 if (ofs > 0) { 273 if (ofs > 0) {
268 html(delim); 274 html(delim);
269 html("ofs="); 275 html("ofs=");
270 htmlf("%d", ofs); 276 htmlf("%d", ofs);
271 } 277 }
272 html("'>"); 278 html("'>");
273 html_txt(name); 279 html_txt(name);
274 html("</a>"); 280 html("</a>");
275} 281}
276 282
277void cgit_commit_link(char *name, char *title, char *class, char *head, 283void cgit_commit_link(char *name, char *title, char *class, char *head,
278 char *rev) 284 char *rev)
279{ 285{
280 if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { 286 if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) {
281 name[ctx.cfg.max_msg_len] = '\0'; 287 name[ctx.cfg.max_msg_len] = '\0';
282 name[ctx.cfg.max_msg_len - 1] = '.'; 288 name[ctx.cfg.max_msg_len - 1] = '.';
283 name[ctx.cfg.max_msg_len - 2] = '.'; 289 name[ctx.cfg.max_msg_len - 2] = '.';
284 name[ctx.cfg.max_msg_len - 3] = '.'; 290 name[ctx.cfg.max_msg_len - 3] = '.';
285 } 291 }
286 reporevlink("commit", name, title, class, head, rev, NULL); 292 reporevlink("commit", name, title, class, head, rev, NULL);
287} 293}
288 294
289void cgit_refs_link(char *name, char *title, char *class, char *head, 295void cgit_refs_link(char *name, char *title, char *class, char *head,
290 char *rev, char *path) 296 char *rev, char *path)
291{ 297{
292 reporevlink("refs", name, title, class, head, rev, path); 298 reporevlink("refs", name, title, class, head, rev, path);
293} 299}
294 300
295void cgit_snapshot_link(char *name, char *title, char *class, char *head, 301void cgit_snapshot_link(char *name, char *title, char *class, char *head,
296 char *rev, char *archivename) 302 char *rev, char *archivename)
297{ 303{
298 reporevlink("snapshot", name, title, class, head, rev, archivename); 304 reporevlink("snapshot", name, title, class, head, rev, archivename);
299} 305}
300 306
301void cgit_diff_link(char *name, char *title, char *class, char *head, 307void cgit_diff_link(char *name, char *title, char *class, char *head,
302 char *new_rev, char *old_rev, char *path) 308 char *new_rev, char *old_rev, char *path)
303{ 309{
304 char *delim; 310 char *delim;
305 311
306 delim = repolink(title, class, "diff", head, path); 312 delim = repolink(title, class, "diff", head, path);
307 if (new_rev && strcmp(new_rev, ctx.qry.head)) { 313 if (new_rev && strcmp(new_rev, ctx.qry.head)) {
308 html(delim); 314 html(delim);
309 html("id="); 315 html("id=");
310 html_attr(new_rev); 316 html_attr(new_rev);
311 delim = "&amp;"; 317 delim = "&amp;";
312 } 318 }
313 if (old_rev) { 319 if (old_rev) {
314 html(delim); 320 html(delim);
315 html("id2="); 321 html("id2=");
316 html_attr(old_rev); 322 html_attr(old_rev);
317 } 323 }
318 html("'>"); 324 html("'>");
319 html_txt(name); 325 html_txt(name);
320 html("</a>"); 326 html("</a>");
321} 327}
322 328
323void cgit_patch_link(char *name, char *title, char *class, char *head, 329void cgit_patch_link(char *name, char *title, char *class, char *head,
324 char *rev) 330 char *rev)
325{ 331{
326 reporevlink("patch", name, title, class, head, rev, NULL); 332 reporevlink("patch", name, title, class, head, rev, NULL);
327} 333}
328 334
329void cgit_object_link(struct object *obj) 335void cgit_object_link(struct object *obj)
330{ 336{
331 char *page, *arg, *url; 337 char *page, *arg, *url;
332 338
333 if (obj->type == OBJ_COMMIT) { 339 if (obj->type == OBJ_COMMIT) {
334 cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL, 340 cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL,
335 ctx.qry.head, sha1_to_hex(obj->sha1)); 341 ctx.qry.head, sha1_to_hex(obj->sha1));
336 return; 342 return;
337 } else if (obj->type == OBJ_TREE) { 343 } else if (obj->type == OBJ_TREE) {
338 page = "tree"; 344 page = "tree";
339 arg = "id"; 345 arg = "id";
340 } else if (obj->type == OBJ_TAG) { 346 } else if (obj->type == OBJ_TAG) {
341 page = "tag"; 347 page = "tag";
342 arg = "id"; 348 arg = "id";
343 } else { 349 } else {
344 page = "blob"; 350 page = "blob";
345 arg = "id"; 351 arg = "id";
346 } 352 }
347 353
348 url = cgit_pageurl(ctx.qry.repo, page, 354 url = cgit_pageurl(ctx.qry.repo, page,
349 fmt("%s=%s", arg, sha1_to_hex(obj->sha1))); 355 fmt("%s=%s", arg, sha1_to_hex(obj->sha1)));
350 html_link_open(url, NULL, NULL); 356 html_link_open(url, NULL, NULL);
351 htmlf("%s %s", typename(obj->type), 357 htmlf("%s %s", typename(obj->type),
352 sha1_to_hex(obj->sha1)); 358 sha1_to_hex(obj->sha1));
353 html_link_close(); 359 html_link_close();
354} 360}
355 361
356void cgit_print_date(time_t secs, char *format, int local_time) 362void cgit_print_date(time_t secs, char *format, int local_time)
357{ 363{
358 char buf[64]; 364 char buf[64];
359 struct tm *time; 365 struct tm *time;
360 366
361 if (!secs) 367 if (!secs)
362 return; 368 return;
363 if(local_time) 369 if(local_time)
364 time = localtime(&secs); 370 time = localtime(&secs);
365 else 371 else
366 time = gmtime(&secs); 372 time = gmtime(&secs);
367 strftime(buf, sizeof(buf)-1, format, time); 373 strftime(buf, sizeof(buf)-1, format, time);
368 html_txt(buf); 374 html_txt(buf);
369} 375}
370 376
371void cgit_print_age(time_t t, time_t max_relative, char *format) 377void cgit_print_age(time_t t, time_t max_relative, char *format)
372{ 378{
373 time_t now, secs; 379 time_t now, secs;
374 380
375 if (!t) 381 if (!t)
376 return; 382 return;
377 time(&now); 383 time(&now);
378 secs = now - t; 384 secs = now - t;
379 385
380 if (secs > max_relative && max_relative >= 0) { 386 if (secs > max_relative && max_relative >= 0) {
381 cgit_print_date(t, format, ctx.cfg.local_time); 387 cgit_print_date(t, format, ctx.cfg.local_time);
382 return; 388 return;
383 } 389 }
384 390
385 if (secs < TM_HOUR * 2) { 391 if (secs < TM_HOUR * 2) {
386 htmlf("<span class='age-mins'>%.0f min.</span>", 392 htmlf("<span class='age-mins'>%.0f min.</span>",
387 secs * 1.0 / TM_MIN); 393 secs * 1.0 / TM_MIN);
388 return; 394 return;
389 } 395 }
390 if (secs < TM_DAY * 2) { 396 if (secs < TM_DAY * 2) {
391 htmlf("<span class='age-hours'>%.0f hours</span>", 397 htmlf("<span class='age-hours'>%.0f hours</span>",
392 secs * 1.0 / TM_HOUR); 398 secs * 1.0 / TM_HOUR);
393 return; 399 return;
394 } 400 }
395 if (secs < TM_WEEK * 2) { 401 if (secs < TM_WEEK * 2) {
396 htmlf("<span class='age-days'>%.0f days</span>", 402 htmlf("<span class='age-days'>%.0f days</span>",
397 secs * 1.0 / TM_DAY); 403 secs * 1.0 / TM_DAY);
398 return; 404 return;
399 } 405 }
400 if (secs < TM_MONTH * 2) { 406 if (secs < TM_MONTH * 2) {
401 htmlf("<span class='age-weeks'>%.0f weeks</span>", 407 htmlf("<span class='age-weeks'>%.0f weeks</span>",
402 secs * 1.0 / TM_WEEK); 408 secs * 1.0 / TM_WEEK);
403 return; 409 return;
404 } 410 }
405 if (secs < TM_YEAR * 2) { 411 if (secs < TM_YEAR * 2) {
406 htmlf("<span class='age-months'>%.0f months</span>", 412 htmlf("<span class='age-months'>%.0f months</span>",
407 secs * 1.0 / TM_MONTH); 413 secs * 1.0 / TM_MONTH);
408 return; 414 return;
409 } 415 }
410 htmlf("<span class='age-years'>%.0f years</span>", 416 htmlf("<span class='age-years'>%.0f years</span>",
411 secs * 1.0 / TM_YEAR); 417 secs * 1.0 / TM_YEAR);
412} 418}
413 419
414void cgit_print_http_headers(struct cgit_context *ctx) 420void cgit_print_http_headers(struct cgit_context *ctx)
415{ 421{
416 if (ctx->page.mimetype && ctx->page.charset) 422 if (ctx->page.mimetype && ctx->page.charset)
417 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype, 423 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype,
418 ctx->page.charset); 424 ctx->page.charset);
419 else if (ctx->page.mimetype) 425 else if (ctx->page.mimetype)
420 htmlf("Content-Type: %s\n", ctx->page.mimetype); 426 htmlf("Content-Type: %s\n", ctx->page.mimetype);
421 if (ctx->page.size) 427 if (ctx->page.size)
422 htmlf("Content-Length: %ld\n", ctx->page.size); 428 htmlf("Content-Length: %ld\n", ctx->page.size);
423 if (ctx->page.filename) 429 if (ctx->page.filename)
424 htmlf("Content-Disposition: inline; filename=\"%s\"\n", 430 htmlf("Content-Disposition: inline; filename=\"%s\"\n",
425 ctx->page.filename); 431 ctx->page.filename);
426 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified)); 432 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified));
427 htmlf("Expires: %s\n", http_date(ctx->page.expires)); 433 htmlf("Expires: %s\n", http_date(ctx->page.expires));
428 html("\n"); 434 html("\n");
429} 435}
430 436
431void cgit_print_docstart(struct cgit_context *ctx) 437void cgit_print_docstart(struct cgit_context *ctx)
432{ 438{
433 html(cgit_doctype); 439 html(cgit_doctype);
434 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n"); 440 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n");
435 html("<head>\n"); 441 html("<head>\n");
436 html("<title>"); 442 html("<title>");
437 html_txt(ctx->page.title); 443 html_txt(ctx->page.title);
438 html("</title>\n"); 444 html("</title>\n");
439 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version); 445 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
440 if (ctx->cfg.robots && *ctx->cfg.robots) 446 if (ctx->cfg.robots && *ctx->cfg.robots)
441 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots); 447 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots);
442 html("<link rel='stylesheet' type='text/css' href='"); 448 html("<link rel='stylesheet' type='text/css' href='");
443 html_attr(ctx->cfg.css); 449 html_attr(ctx->cfg.css);
444 html("'/>\n"); 450 html("'/>\n");
445 if (ctx->cfg.favicon) { 451 if (ctx->cfg.favicon) {
446 html("<link rel='shortcut icon' href='"); 452 html("<link rel='shortcut icon' href='");
447 html_attr(ctx->cfg.favicon); 453 html_attr(ctx->cfg.favicon);
448 html("'/>\n"); 454 html("'/>\n");
449 } 455 }
450 html("</head>\n"); 456 html("</head>\n");
451 html("<body>\n"); 457 html("<body>\n");
452} 458}
453 459
454void cgit_print_docend() 460void cgit_print_docend()
455{ 461{
456 html("</div>"); 462 html("</div>");
457 if (ctx.cfg.footer) 463 if (ctx.cfg.footer)
458 html_include(ctx.cfg.footer); 464 html_include(ctx.cfg.footer);
459 else { 465 else {
460 html("<div class='footer'>generated "); 466 html("<div class='footer'>generated ");
461 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time); 467 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time);
462 htmlf(" by cgit %s", cgit_version); 468 htmlf(" by cgit %s", cgit_version);
463 html("</div>\n"); 469 html("</div>\n");
464 } 470 }
465 html("</body>\n</html>\n"); 471 html("</body>\n</html>\n");
466} 472}
467 473
468int print_branch_option(const char *refname, const unsigned char *sha1, 474int print_branch_option(const char *refname, const unsigned char *sha1,
469 int flags, void *cb_data) 475 int flags, void *cb_data)
470{ 476{
471 char *name = (char *)refname; 477 char *name = (char *)refname;
472 html_option(name, name, ctx.qry.head); 478 html_option(name, name, ctx.qry.head);
473 return 0; 479 return 0;
474} 480}
475 481
476int print_archive_ref(const char *refname, const unsigned char *sha1, 482int print_archive_ref(const char *refname, const unsigned char *sha1,
477 int flags, void *cb_data) 483 int flags, void *cb_data)
478{ 484{
479 struct tag *tag; 485 struct tag *tag;
480 struct taginfo *info; 486 struct taginfo *info;
481 struct object *obj; 487 struct object *obj;
482 char buf[256], *url; 488 char buf[256], *url;
483 unsigned char fileid[20]; 489 unsigned char fileid[20];
484 int *header = (int *)cb_data; 490 int *header = (int *)cb_data;
485 491
486 if (prefixcmp(refname, "refs/archives")) 492 if (prefixcmp(refname, "refs/archives"))
487 return 0; 493 return 0;
488 strncpy(buf, refname+14, sizeof(buf)); 494 strncpy(buf, refname+14, sizeof(buf));
489 obj = parse_object(sha1); 495 obj = parse_object(sha1);
490 if (!obj) 496 if (!obj)
491 return 1; 497 return 1;
492 if (obj->type == OBJ_TAG) { 498 if (obj->type == OBJ_TAG) {
493 tag = lookup_tag(sha1); 499 tag = lookup_tag(sha1);
494 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 500 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
495 return 0; 501 return 0;
496 hashcpy(fileid, tag->tagged->sha1); 502 hashcpy(fileid, tag->tagged->sha1);
497 } else if (obj->type != OBJ_BLOB) { 503 } else if (obj->type != OBJ_BLOB) {
498 return 0; 504 return 0;
499 } else { 505 } else {
500 hashcpy(fileid, sha1); 506 hashcpy(fileid, sha1);
501 } 507 }