summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2006-12-11 15:38:30 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2006-12-11 15:38:30 (UTC)
commit5a106eb09b9b5e189b96cc736046a92b054f6c7f (patch) (unidiff)
tree7172123df870c07deb882a4993fa991b31fc9008
parent51ada4fda2b47710351e6e4da8a95807d6d9f729 (diff)
downloadcgit-5a106eb09b9b5e189b96cc736046a92b054f6c7f.zip
cgit-5a106eb09b9b5e189b96cc736046a92b054f6c7f.tar.gz
cgit-5a106eb09b9b5e189b96cc736046a92b054f6c7f.tar.bz2
Move common output-functions into ui-shared.c
While at it, replace the cgit_[lib_]error constants with a proper function Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--Makefile2
-rw-r--r--cgit.c94
-rw-r--r--cgit.h9
-rw-r--r--ui-shared.c76
4 files changed, 99 insertions, 82 deletions
diff --git a/Makefile b/Makefile
index eab7926..a4291f7 100644
--- a/Makefile
+++ b/Makefile
@@ -1,27 +1,27 @@
1CGIT_VERSION = 0.1-pre 1CGIT_VERSION = 0.1-pre
2 2
3INSTALL_BIN = /var/www/htdocs/cgit.cgi 3INSTALL_BIN = /var/www/htdocs/cgit.cgi
4INSTALL_CSS = /var/www/htdocs/cgit.css 4INSTALL_CSS = /var/www/htdocs/cgit.css
5CACHE_ROOT = /var/cache/cgit 5CACHE_ROOT = /var/cache/cgit
6 6
7EXTLIBS = ../git/libgit.a ../git/xdiff/lib.a -lz -lcrypto 7EXTLIBS = ../git/libgit.a ../git/xdiff/lib.a -lz -lcrypto
8OBJECTS = parsing.o html.o cache.o 8OBJECTS = parsing.o html.o cache.o ui-shared.o
9 9
10CFLAGS += -Wall 10CFLAGS += -Wall
11 11
12all: cgit 12all: cgit
13 13
14install: all 14install: all
15 install cgit $(INSTALL_BIN) 15 install cgit $(INSTALL_BIN)
16 install cgit.css $(INSTALL_CSS) 16 install cgit.css $(INSTALL_CSS)
17 rm -rf $(CACHE_ROOT)/* 17 rm -rf $(CACHE_ROOT)/*
18 18
19cgit: cgit.c cgit.h git.h $(OBJECTS) 19cgit: cgit.c cgit.h git.h $(OBJECTS)
20 $(CC) $(CFLAGS) -DCGIT_VERSION='"$(CGIT_VERSION)"' cgit.c -o cgit \ 20 $(CC) $(CFLAGS) -DCGIT_VERSION='"$(CGIT_VERSION)"' cgit.c -o cgit \
21 $(OBJECTS) $(EXTLIBS) 21 $(OBJECTS) $(EXTLIBS)
22 22
23$(OBJECTS): cgit.h git.h 23$(OBJECTS): cgit.h git.h
24 24
25.PHONY: clean 25.PHONY: clean
26clean: 26clean:
27 rm -f cgit *.o 27 rm -f cgit *.o
diff --git a/cgit.c b/cgit.c
index 5567859..5438fa1 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,46 +1,36 @@
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
13const char cgit_doctype[] =
14"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
15" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
16
17const char cgit_error[] =
18"<div class='error'>%s</div>";
19
20const char cgit_lib_error[] =
21"<div class='error'>%s: %s</div>";
22
23int htmlfd = 0; 13int htmlfd = 0;
24 14
25char *cgit_root = "/usr/src/git"; 15char *cgit_root = "/usr/src/git";
26char *cgit_root_title = "Git repository browser"; 16char *cgit_root_title = "Git repository browser";
27char *cgit_css = "/cgit.css"; 17char *cgit_css = "/cgit.css";
28char *cgit_logo = "/git-logo.png"; 18char *cgit_logo = "/git-logo.png";
29char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/"; 19char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/";
30char *cgit_virtual_root = NULL; 20char *cgit_virtual_root = NULL;
31 21
32char *cgit_cache_root = "/var/cache/cgit"; 22char *cgit_cache_root = "/var/cache/cgit";
33 23
34int cgit_max_lock_attempts = 5; 24int cgit_max_lock_attempts = 5;
35int cgit_cache_root_ttl = 5; 25int cgit_cache_root_ttl = 5;
36int cgit_cache_repo_ttl = 5; 26int cgit_cache_repo_ttl = 5;
37int cgit_cache_dynamic_ttl = 5; 27int cgit_cache_dynamic_ttl = 5;
38int cgit_cache_static_ttl = -1; 28int cgit_cache_static_ttl = -1;
39int cgit_cache_max_create_time = 5; 29int cgit_cache_max_create_time = 5;
40 30
41char *cgit_repo_name = NULL; 31char *cgit_repo_name = NULL;
42char *cgit_repo_desc = NULL; 32char *cgit_repo_desc = NULL;
43char *cgit_repo_owner = NULL; 33char *cgit_repo_owner = NULL;
44 34
45int cgit_query_has_symref = 0; 35int cgit_query_has_symref = 0;
46int cgit_query_has_sha1 = 0; 36int cgit_query_has_sha1 = 0;
@@ -123,118 +113,62 @@ static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1,
123 commit = lookup_commit(sha1); 113 commit = lookup_commit(sha1);
124 if (commit && !parse_commit(commit)){ 114 if (commit && !parse_commit(commit)){
125 html("<tr><td>"); 115 html("<tr><td>");
126 url = cgit_pageurl(cgit_query_repo, "log", 116 url = cgit_pageurl(cgit_query_repo, "log",
127 fmt("h=%s", refname)); 117 fmt("h=%s", refname));
128 html_link_open(url, NULL, NULL); 118 html_link_open(url, NULL, NULL);
129 strncpy(buf, refname, sizeof(buf)); 119 strncpy(buf, refname, sizeof(buf));
130 html_txt(buf); 120 html_txt(buf);
131 html_link_close(); 121 html_link_close();
132 html("</td><td>"); 122 html("</td><td>");
133 pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, buf, 123 pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, buf,
134 sizeof(buf), 0, NULL, NULL, 0); 124 sizeof(buf), 0, NULL, NULL, 0);
135 html_txt(buf); 125 html_txt(buf);
136 html("</td></tr>\n"); 126 html("</td></tr>\n");
137 } else { 127 } else {
138 html("<tr><td>"); 128 html("<tr><td>");
139 html_txt(buf); 129 html_txt(buf);
140 html("</td><td>"); 130 html("</td><td>");
141 htmlf("*** bad ref %s", sha1_to_hex(sha1)); 131 htmlf("*** bad ref %s", sha1_to_hex(sha1));
142 html("</td></tr>\n"); 132 html("</td></tr>\n");
143 } 133 }
144 return 0; 134 return 0;
145} 135}
146 136
147/* Sun, 06 Nov 1994 08:49:37 GMT */ 137static void cgit_print_repolist(struct cacheitem *item)
148static char *http_date(time_t t)
149{
150 static char day[][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
151 static char month[][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
152 "Jul", "Aug", "Sep", "Oct", "Now", "Dec"};
153 struct tm *tm = gmtime(&t);
154 return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday],
155 tm->tm_mday, month[tm->tm_mon], 1900+tm->tm_year,
156 tm->tm_hour, tm->tm_min, tm->tm_sec);
157}
158
159static int ttl_seconds(int ttl)
160{
161 if (ttl<0)
162 return 60 * 60 * 24 * 365;
163 else
164 return ttl * 60;
165}
166
167static void cgit_print_docstart(char *title)
168{
169 html("Content-Type: text/html; charset=utf-8\n");
170 htmlf("Last-Modified: %s\n", http_date(cacheitem.st.st_mtime));
171 htmlf("Expires: %s\n", http_date(cacheitem.st.st_mtime +
172 ttl_seconds(cacheitem.ttl)));
173 html("\n");
174 html(cgit_doctype);
175 html("<html>\n");
176 html("<head>\n");
177 html("<title>");
178 html_txt(title);
179 html("</title>\n");
180 htmlf("<meta name='generator' content='cgit v%s'/>\n", cgit_version);
181 html("<link rel='stylesheet' type='text/css' href='");
182 html_attr(cgit_css);
183 html("'/>\n");
184 html("</head>\n");
185 html("<body>\n");
186}
187
188static void cgit_print_docend()
189{
190 html("</body>\n</html>\n");
191}
192
193static void cgit_print_pageheader(char *title)
194{
195 html("<div id='header'>");
196 htmlf("<a href='%s'>", cgit_logo_link);
197 htmlf("<img id='logo' src='%s'/>\n", cgit_logo);
198 htmlf("</a>");
199 html_txt(title);
200 html("</div>");
201}
202
203static void cgit_print_repolist()
204{ 138{
205 DIR *d; 139 DIR *d;
206 struct dirent *de; 140 struct dirent *de;
207 struct stat st; 141 struct stat st;
208 char *name; 142 char *name;
209 143
210 chdir(cgit_root); 144 chdir(cgit_root);
211 cgit_print_docstart(cgit_root_title); 145 cgit_print_docstart(cgit_root_title, item);
212 cgit_print_pageheader(cgit_root_title); 146 cgit_print_pageheader(cgit_root_title);
213 147
214 if (!(d = opendir("."))) { 148 if (!(d = opendir("."))) {
215 htmlf(cgit_lib_error, "Unable to scan repository directory", 149 cgit_print_error(fmt("Unable to scan repository directory: %s",
216 strerror(errno)); 150 strerror(errno)));
217 cgit_print_docend(); 151 cgit_print_docend();
218 return; 152 return;
219 } 153 }
220 154
221 html("<h2>Repositories</h2>\n"); 155 html("<h2>Repositories</h2>\n");
222 html("<table class='list'>"); 156 html("<table class='list'>");
223 html("<tr><th>Name</th><th>Description</th><th>Owner</th></tr>\n"); 157 html("<tr><th>Name</th><th>Description</th><th>Owner</th></tr>\n");
224 while ((de = readdir(d)) != NULL) { 158 while ((de = readdir(d)) != NULL) {
225 if (de->d_name[0] == '.') 159 if (de->d_name[0] == '.')
226 continue; 160 continue;
227 if (stat(de->d_name, &st) < 0) 161 if (stat(de->d_name, &st) < 0)
228 continue; 162 continue;
229 if (!S_ISDIR(st.st_mode)) 163 if (!S_ISDIR(st.st_mode))
230 continue; 164 continue;
231 165
232 cgit_repo_name = cgit_repo_desc = cgit_repo_owner = NULL; 166 cgit_repo_name = cgit_repo_desc = cgit_repo_owner = NULL;
233 name = fmt("%s/info/cgit", de->d_name); 167 name = fmt("%s/info/cgit", de->d_name);
234 if (cgit_read_config(name, cgit_repo_config_cb)) 168 if (cgit_read_config(name, cgit_repo_config_cb))
235 continue; 169 continue;
236 170
237 html("<tr><td>"); 171 html("<tr><td>");
238 html_link_open(cgit_repourl(de->d_name), NULL, NULL); 172 html_link_open(cgit_repourl(de->d_name), NULL, NULL);
239 html_txt(cgit_repo_name); 173 html_txt(cgit_repo_name);
240 html_link_close(); 174 html_link_close();
@@ -358,105 +292,105 @@ static void cgit_print_log(const char *tip, int ofs, int cnt)
358 commit->buffer = NULL; 292 commit->buffer = NULL;
359 free_commit_list(commit->parents); 293 free_commit_list(commit->parents);
360 commit->parents = NULL; 294 commit->parents = NULL;
361 } 295 }
362 html("</table>\n"); 296 html("</table>\n");
363} 297}
364 298
365static void cgit_print_repo_summary() 299static void cgit_print_repo_summary()
366{ 300{
367 html("<h2>"); 301 html("<h2>");
368 html_txt("Repo summary page"); 302 html_txt("Repo summary page");
369 html("</h2>"); 303 html("</h2>");
370 cgit_print_branches(); 304 cgit_print_branches();
371} 305}
372 306
373static void cgit_print_object(char *hex) 307static void cgit_print_object(char *hex)
374{ 308{
375 unsigned char sha1[20]; 309 unsigned char sha1[20];
376 //struct object *object; 310 //struct object *object;
377 char type[20]; 311 char type[20];
378 unsigned char *buf; 312 unsigned char *buf;
379 unsigned long size; 313 unsigned long size;
380 314
381 if (get_sha1_hex(hex, sha1)){ 315 if (get_sha1_hex(hex, sha1)){
382 htmlf(cgit_error, "Bad hex value"); 316 cgit_print_error(fmt("Bad hex value: %s", hex));
383 return; 317 return;
384 } 318 }
385 319
386 if (sha1_object_info(sha1, type, NULL)){ 320 if (sha1_object_info(sha1, type, NULL)){
387 htmlf(cgit_error, "Bad object name"); 321 cgit_print_error("Bad object name");
388 return; 322 return;
389 } 323 }
390 324
391 buf = read_sha1_file(sha1, type, &size); 325 buf = read_sha1_file(sha1, type, &size);
392 if (!buf) { 326 if (!buf) {
393 htmlf(cgit_error, "Error reading object"); 327 cgit_print_error("Error reading object");
394 return; 328 return;
395 } 329 }
396 330
397 buf[size] = '\0'; 331 buf[size] = '\0';
398 html("<h2>Object view</h2>"); 332 html("<h2>Object view</h2>");
399 htmlf("sha1=%s<br/>type=%s<br/>size=%i<br/>", hex, type, size); 333 htmlf("sha1=%s<br/>type=%s<br/>size=%i<br/>", hex, type, size);
400 html("<pre>"); 334 html("<pre>");
401 html_txt(buf); 335 html_txt(buf);
402 html("</pre>"); 336 html("</pre>");
403} 337}
404 338
405static void cgit_print_repo_page() 339static void cgit_print_repo_page(struct cacheitem *item)
406{ 340{
407 if (chdir(fmt("%s/%s", cgit_root, cgit_query_repo)) || 341 if (chdir(fmt("%s/%s", cgit_root, cgit_query_repo)) ||
408 cgit_read_config("info/cgit", cgit_repo_config_cb)) { 342 cgit_read_config("info/cgit", cgit_repo_config_cb)) {
409 char *title = fmt("%s - %s", cgit_root_title, "Bad request"); 343 char *title = fmt("%s - %s", cgit_root_title, "Bad request");
410 cgit_print_docstart(title); 344 cgit_print_docstart(title, item);
411 cgit_print_pageheader(title); 345 cgit_print_pageheader(title);
412 htmlf(cgit_lib_error, "Unable to scan repository", 346 cgit_print_error(fmt("Unable to scan repository: %s",
413 strerror(errno)); 347 strerror(errno)));
414 cgit_print_docend(); 348 cgit_print_docend();
415 return; 349 return;
416 } 350 }
417 setenv("GIT_DIR", fmt("%s/%s", cgit_root, cgit_query_repo), 1); 351 setenv("GIT_DIR", fmt("%s/%s", cgit_root, cgit_query_repo), 1);
418 char *title = fmt("%s - %s", cgit_repo_name, cgit_repo_desc); 352 char *title = fmt("%s - %s", cgit_repo_name, cgit_repo_desc);
419 cgit_print_docstart(title); 353 cgit_print_docstart(title, item);
420 cgit_print_pageheader(title); 354 cgit_print_pageheader(title);
421 if (!cgit_query_page) 355 if (!cgit_query_page)
422 cgit_print_repo_summary(); 356 cgit_print_repo_summary();
423 else if (!strcmp(cgit_query_page, "log")) { 357 else if (!strcmp(cgit_query_page, "log")) {
424 cgit_print_log(cgit_query_head, 0, 100); 358 cgit_print_log(cgit_query_head, 0, 100);
425 } else if (!strcmp(cgit_query_page, "view")) { 359 } else if (!strcmp(cgit_query_page, "view")) {
426 cgit_print_object(cgit_query_sha1); 360 cgit_print_object(cgit_query_sha1);
427 } 361 }
428 cgit_print_docend(); 362 cgit_print_docend();
429} 363}
430 364
431static void cgit_fill_cache(struct cacheitem *item) 365static void cgit_fill_cache(struct cacheitem *item)
432{ 366{
433 htmlfd = item->fd; 367 htmlfd = item->fd;
434 item->st.st_mtime = time(NULL); 368 item->st.st_mtime = time(NULL);
435 if (cgit_query_repo) 369 if (cgit_query_repo)
436 cgit_print_repo_page(); 370 cgit_print_repo_page(item);
437 else 371 else
438 cgit_print_repolist(); 372 cgit_print_repolist(item);
439} 373}
440 374
441static void cgit_refresh_cache(struct cacheitem *item) 375static void cgit_refresh_cache(struct cacheitem *item)
442{ 376{
443 int i = 0; 377 int i = 0;
444 378
445 cache_prepare(item); 379 cache_prepare(item);
446 top: 380 top:
447 if (++i > cgit_max_lock_attempts) { 381 if (++i > cgit_max_lock_attempts) {
448 die("cgit_refresh_cache: unable to lock %s: %s", 382 die("cgit_refresh_cache: unable to lock %s: %s",
449 item->name, strerror(errno)); 383 item->name, strerror(errno));
450 } 384 }
451 if (!cache_exist(item)) { 385 if (!cache_exist(item)) {
452 if (!cache_lock(item)) { 386 if (!cache_lock(item)) {
453 sleep(1); 387 sleep(1);
454 goto top; 388 goto top;
455 } 389 }
456 if (!cache_exist(item)) 390 if (!cache_exist(item))
457 cgit_fill_cache(item); 391 cgit_fill_cache(item);
458 cache_unlock(item); 392 cache_unlock(item);
459 } else if (cache_expired(item) && cache_lock(item)) { 393 } else if (cache_expired(item) && cache_lock(item)) {
460 if (cache_expired(item)) 394 if (cache_expired(item))
461 cgit_fill_cache(item); 395 cgit_fill_cache(item);
462 cache_unlock(item); 396 cache_unlock(item);
diff --git a/cgit.h b/cgit.h
index 6c0aa3b..e64fbd7 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,67 +1,74 @@
1#ifndef CGIT_H 1#ifndef CGIT_H
2#define CGIT_H 2#define CGIT_H
3 3
4#include "git.h" 4#include "git.h"
5#include <openssl/sha.h> 5#include <openssl/sha.h>
6#include <ctype.h> 6#include <ctype.h>
7#include <sched.h> 7#include <sched.h>
8 8
9typedef void (*configfn)(const char *name, const char *value); 9typedef void (*configfn)(const char *name, const char *value);
10 10
11struct cacheitem { 11struct cacheitem {
12 char *name; 12 char *name;
13 struct stat st; 13 struct stat st;
14 int ttl; 14 int ttl;
15 int fd; 15 int fd;
16}; 16};
17 17
18extern const char cgit_version[];
19
18extern char *cgit_root; 20extern char *cgit_root;
19extern char *cgit_root_title; 21extern char *cgit_root_title;
20extern char *cgit_css; 22extern char *cgit_css;
21extern char *cgit_logo; 23extern char *cgit_logo;
22extern char *cgit_logo_link; 24extern char *cgit_logo_link;
23extern char *cgit_virtual_root; 25extern char *cgit_virtual_root;
24extern char *cgit_cache_root; 26extern char *cgit_cache_root;
25 27
26extern int cgit_max_lock_attempts; 28extern int cgit_max_lock_attempts;
27extern int cgit_cache_root_ttl; 29extern int cgit_cache_root_ttl;
28extern int cgit_cache_repo_ttl; 30extern int cgit_cache_repo_ttl;
29extern int cgit_cache_dynamic_ttl; 31extern int cgit_cache_dynamic_ttl;
30extern int cgit_cache_static_ttl; 32extern int cgit_cache_static_ttl;
31extern int cgit_cache_max_create_time; 33extern int cgit_cache_max_create_time;
32 34
33extern char *cgit_repo_name; 35extern char *cgit_repo_name;
34extern char *cgit_repo_desc; 36extern char *cgit_repo_desc;
35extern char *cgit_repo_owner; 37extern char *cgit_repo_owner;
36 38
37extern int cgit_query_has_symref; 39extern int cgit_query_has_symref;
38extern int cgit_query_has_sha1; 40extern int cgit_query_has_sha1;
39 41
40extern char *cgit_querystring; 42extern char *cgit_querystring;
41extern char *cgit_query_repo; 43extern char *cgit_query_repo;
42extern char *cgit_query_page; 44extern char *cgit_query_page;
43extern char *cgit_query_head; 45extern char *cgit_query_head;
44extern char *cgit_query_sha1; 46extern char *cgit_query_sha1;
45 47
46extern int htmlfd; 48extern int htmlfd;
47 49
48extern char *fmt(const char *format,...); 50extern char *fmt(const char *format,...);
49 51
50extern void html(const char *txt); 52extern void html(const char *txt);
51extern void htmlf(const char *format,...); 53extern void htmlf(const char *format,...);
52extern void html_txt(char *txt); 54extern void html_txt(char *txt);
53extern void html_attr(char *txt); 55extern void html_attr(char *txt);
54extern void html_link_open(char *url, char *title, char *class); 56extern void html_link_open(char *url, char *title, char *class);
55extern void html_link_close(void); 57extern void html_link_close(void);
56 58
57
58extern int cgit_read_config(const char *filename, configfn fn); 59extern int cgit_read_config(const char *filename, configfn fn);
59extern int cgit_parse_query(char *txt, configfn fn); 60extern int cgit_parse_query(char *txt, configfn fn);
60 61
61extern void cache_prepare(struct cacheitem *item); 62extern void cache_prepare(struct cacheitem *item);
62extern int cache_lock(struct cacheitem *item); 63extern int cache_lock(struct cacheitem *item);
63extern int cache_unlock(struct cacheitem *item); 64extern int cache_unlock(struct cacheitem *item);
64extern int cache_exist(struct cacheitem *item); 65extern int cache_exist(struct cacheitem *item);
65extern int cache_expired(struct cacheitem *item); 66extern int cache_expired(struct cacheitem *item);
66 67
68extern void cgit_print_error(char *msg);
69extern void cgit_print_docstart(char *title, struct cacheitem *item);
70extern void cgit_print_docend();
71extern void cgit_print_pageheader(char *title);
72
73
67#endif /* CGIT_H */ 74#endif /* CGIT_H */
diff --git a/ui-shared.c b/ui-shared.c
new file mode 100644
index 0000000..e795043
--- a/dev/null
+++ b/ui-shared.c
@@ -0,0 +1,76 @@
1/* ui-shared.c: common web output functions
2 *
3 * Copyright (C) 2006 Lars Hjemli
4 *
5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text)
7 */
8
9#include "cgit.h"
10
11const char cgit_doctype[] =
12"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
13" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
14
15static char *http_date(time_t t)
16{
17 static char day[][4] =
18 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
19 static char month[][4] =
20 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
21 "Jul", "Aug", "Sep", "Oct", "Now", "Dec"};
22 struct tm *tm = gmtime(&t);
23 return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday],
24 tm->tm_mday, month[tm->tm_mon], 1900+tm->tm_year,
25 tm->tm_hour, tm->tm_min, tm->tm_sec);
26}
27
28static int ttl_seconds(int ttl)
29{
30 if (ttl<0)
31 return 60 * 60 * 24 * 365;
32 else
33 return ttl * 60;
34}
35
36void cgit_print_error(char *msg)
37{
38 html("<div class='error'>");
39 html_txt(msg);
40 html("</div>\n");
41}
42void cgit_print_docstart(char *title, struct cacheitem *item)
43{
44 html("Content-Type: text/html; charset=utf-8\n");
45 htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime));
46 htmlf("Expires: %s\n", http_date(item->st.st_mtime +
47 ttl_seconds(item->ttl)));
48 html("\n");
49 html(cgit_doctype);
50 html("<html>\n");
51 html("<head>\n");
52 html("<title>");
53 html_txt(title);
54 html("</title>\n");
55 htmlf("<meta name='generator' content='cgit v%s'/>\n", cgit_version);
56 html("<link rel='stylesheet' type='text/css' href='");
57 html_attr(cgit_css);
58 html("'/>\n");
59 html("</head>\n");
60 html("<body>\n");
61}
62
63void cgit_print_docend()
64{
65 html("</body>\n</html>\n");
66}
67
68void cgit_print_pageheader(char *title)
69{
70 html("<div id='header'>");
71 htmlf("<a href='%s'>", cgit_logo_link);
72 htmlf("<img id='logo' src='%s'/>\n", cgit_logo);
73 htmlf("</a>");
74 html_txt(title);
75 html("</div>");
76}