summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--Makefile2
-rw-r--r--cgit.c2
-rw-r--r--cgit.css50
-rw-r--r--cgit.h5
-rw-r--r--parsing.c1
-rw-r--r--ui-commit.c80
-rw-r--r--ui-log.c11
-rw-r--r--ui-tree.c6
-rw-r--r--ui-view.c2
9 files changed, 140 insertions, 19 deletions
diff --git a/Makefile b/Makefile
index 2a4d62a..58a583b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,30 +1,30 @@
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 = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \ 8OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \
9 ui-summary.o ui-log.o ui-view.c ui-tree.c 9 ui-summary.o ui-log.o ui-view.c ui-tree.c ui-commit.c
10 10
11CFLAGS += -Wall 11CFLAGS += -Wall
12 12
13all: cgit 13all: cgit
14 14
15install: all clean-cache 15install: all clean-cache
16 install cgit $(INSTALL_BIN) 16 install cgit $(INSTALL_BIN)
17 install cgit.css $(INSTALL_CSS) 17 install cgit.css $(INSTALL_CSS)
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
28 28
29clean-cache: 29clean-cache:
30 rm -rf $(CACHE_ROOT)/* 30 rm -rf $(CACHE_ROOT)/*
diff --git a/cgit.c b/cgit.c
index d7e586d..37cdb83 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,82 +1,84 @@
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
13static void cgit_print_repo_page(struct cacheitem *item) 13static void cgit_print_repo_page(struct cacheitem *item)
14{ 14{
15 if (chdir(fmt("%s/%s", cgit_root, cgit_query_repo)) || 15 if (chdir(fmt("%s/%s", cgit_root, cgit_query_repo)) ||
16 cgit_read_config("info/cgit", cgit_repo_config_cb)) { 16 cgit_read_config("info/cgit", cgit_repo_config_cb)) {
17 char *title = fmt("%s - %s", cgit_root_title, "Bad request"); 17 char *title = fmt("%s - %s", cgit_root_title, "Bad request");
18 cgit_print_docstart(title, item); 18 cgit_print_docstart(title, item);
19 cgit_print_pageheader(title); 19 cgit_print_pageheader(title);
20 cgit_print_error(fmt("Unable to scan repository: %s", 20 cgit_print_error(fmt("Unable to scan repository: %s",
21 strerror(errno))); 21 strerror(errno)));
22 cgit_print_docend(); 22 cgit_print_docend();
23 return; 23 return;
24 } 24 }
25 setenv("GIT_DIR", fmt("%s/%s", cgit_root, cgit_query_repo), 1); 25 setenv("GIT_DIR", fmt("%s/%s", cgit_root, cgit_query_repo), 1);
26 char *title = fmt("%s - %s", cgit_repo_name, cgit_repo_desc); 26 char *title = fmt("%s - %s", cgit_repo_name, cgit_repo_desc);
27 cgit_print_docstart(title, item); 27 cgit_print_docstart(title, item);
28 cgit_print_pageheader(title); 28 cgit_print_pageheader(title);
29 if (!cgit_query_page) { 29 if (!cgit_query_page) {
30 cgit_print_summary(); 30 cgit_print_summary();
31 } else if (!strcmp(cgit_query_page, "log")) { 31 } else if (!strcmp(cgit_query_page, "log")) {
32 cgit_print_log(cgit_query_head, cgit_query_ofs, 100); 32 cgit_print_log(cgit_query_head, cgit_query_ofs, 100);
33 } else if (!strcmp(cgit_query_page, "tree")) { 33 } else if (!strcmp(cgit_query_page, "tree")) {
34 cgit_print_tree(cgit_query_sha1); 34 cgit_print_tree(cgit_query_sha1);
35 } else if (!strcmp(cgit_query_page, "commit")) {
36 cgit_print_commit(cgit_query_sha1);
35 } else if (!strcmp(cgit_query_page, "view")) { 37 } else if (!strcmp(cgit_query_page, "view")) {
36 cgit_print_view(cgit_query_sha1); 38 cgit_print_view(cgit_query_sha1);
37 } 39 }
38 cgit_print_docend(); 40 cgit_print_docend();
39} 41}
40 42
41static void cgit_fill_cache(struct cacheitem *item) 43static void cgit_fill_cache(struct cacheitem *item)
42{ 44{
43 htmlfd = item->fd; 45 htmlfd = item->fd;
44 item->st.st_mtime = time(NULL); 46 item->st.st_mtime = time(NULL);
45 if (cgit_query_repo) 47 if (cgit_query_repo)
46 cgit_print_repo_page(item); 48 cgit_print_repo_page(item);
47 else 49 else
48 cgit_print_repolist(item); 50 cgit_print_repolist(item);
49} 51}
50 52
51static void cgit_check_cache(struct cacheitem *item) 53static void cgit_check_cache(struct cacheitem *item)
52{ 54{
53 int i = 0; 55 int i = 0;
54 56
55 cache_prepare(item); 57 cache_prepare(item);
56 top: 58 top:
57 if (++i > cgit_max_lock_attempts) { 59 if (++i > cgit_max_lock_attempts) {
58 die("cgit_refresh_cache: unable to lock %s: %s", 60 die("cgit_refresh_cache: unable to lock %s: %s",
59 item->name, strerror(errno)); 61 item->name, strerror(errno));
60 } 62 }
61 if (!cache_exist(item)) { 63 if (!cache_exist(item)) {
62 if (!cache_lock(item)) { 64 if (!cache_lock(item)) {
63 sleep(1); 65 sleep(1);
64 goto top; 66 goto top;
65 } 67 }
66 if (!cache_exist(item)) { 68 if (!cache_exist(item)) {
67 cgit_fill_cache(item); 69 cgit_fill_cache(item);
68 cache_unlock(item); 70 cache_unlock(item);
69 } else { 71 } else {
70 cache_cancel_lock(item); 72 cache_cancel_lock(item);
71 } 73 }
72 } else if (cache_expired(item) && cache_lock(item)) { 74 } else if (cache_expired(item) && cache_lock(item)) {
73 if (cache_expired(item)) { 75 if (cache_expired(item)) {
74 cgit_fill_cache(item); 76 cgit_fill_cache(item);
75 cache_unlock(item); 77 cache_unlock(item);
76 } else { 78 } else {
77 cache_cancel_lock(item); 79 cache_cancel_lock(item);
78 } 80 }
79 } 81 }
80} 82}
81 83
82static void cgit_print_cache(struct cacheitem *item) 84static void cgit_print_cache(struct cacheitem *item)
diff --git a/cgit.css b/cgit.css
index 97b4e27..3579598 100644
--- a/cgit.css
+++ b/cgit.css
@@ -1,78 +1,120 @@
1body { 1body {
2 font-family: arial; 2 font-family: arial;
3 font-size: normal; 3 font-size: normal;
4 background: white; 4 background: white;
5 padding: 0em; 5 padding: 0em;
6 margin: 0.5em; 6 margin: 0.5em;
7} 7}
8 8
9 9
10h2 { 10h2 {
11 font-size: normal; 11 font-size: normal;
12 font-weight: bold; 12 font-weight: bold;
13 margin-bottom: 0.1em; 13 margin-bottom: 0.1em;
14} 14}
15 15
16 16
17table.list { 17table.list {
18 border: solid 1px black; 18 border: solid 1px black;
19 border-collapse: collapse; 19 border-collapse: collapse;
20 border: solid 1px #aaa; 20 border: solid 1px #aaa;
21} 21}
22 22
23table.list th { 23table.list th {
24 text-align: left;
25 font-weight: bold; 24 font-weight: bold;
26 background: #ddd; 25 background: #ddd;
27 border-bottom: solid 1px #aaa; 26 border-bottom: solid 1px #aaa;
28 padding: 0.1em 0.5em 0.1em; 27 padding: 0.1em 0.5em 0.1em 0.5em;
29 vertical-align: baseline; 28 vertical-align: baseline;
30} 29}
31table.list td { 30table.list td {
32 border: none; 31 border: none;
33 padding: 0.1em 1em 0.1em 0.5em; 32 padding: 0.1em 0.5em 0.1em 0.5em;
34 background: white; 33 background: white;
35} 34}
36 35
37img { 36img {
38 border: none; 37 border: none;
39} 38}
40 39
41 40
42div#header { 41div#header {
43 background-color: #ddd; 42 background-color: #ddd;
44 padding: 0.25em 0.25em 0.25em 0.5em; 43 padding: 0.25em 0.25em 0.25em 0.5em;
45 font-size: 150%; 44 font-size: 150%;
46 font-weight: bold; 45 font-weight: bold;
47 border: solid 1px #aaa; 46 border: solid 1px #aaa;
48 vertical-align: middle; 47 vertical-align: middle;
49} 48}
50 49
51div#header img#logo { 50div#header img#logo {
52 float: right; 51 float: right;
53} 52}
54 53
55div#content { 54div#content {
56 margin: 0.5em 0.5em; 55 margin: 0.5em 0.5em;
57} 56}
58 57
58div#blob {
59 border: solid 1px black;
60}
61
59div.error { 62div.error {
60 color: red; 63 color: red;
61 font-weight: bold; 64 font-weight: bold;
62 margin: 1em 2em; 65 margin: 1em 2em;
63} 66}
64div.ls-dir a { 67div.ls-dir a {
65 font-weight: bold; 68 font-weight: bold;
66} 69}
67th.filesize, td.filesize { 70th.filesize, td.filesize {
68 text-align: right; 71 text-align: right;
69} 72}
70th.filemode, td.filemode { 73th.filemode, td.filemode {
71 text-align: center; 74 text-align: center;
72} 75}
73 76
74td.blob { 77td.blob {
75 white-space: pre; 78 white-space: pre;
76 font-family: courier; 79 font-family: courier;
77 font-size: 100%; 80 font-size: 100%;
78} \ No newline at end of file 81}
82
83table.log td {
84 white-space: nowrap;
85}
86
87table.commit-info {
88 border-collapse: collapse;
89 margin-top: 1em;
90
91}
92table.commit-info th {
93 text-align: left;
94 font-weight: normal;
95 padding: 0.1em 1em 0.1em 0.1em;
96}
97table.commit-info td {
98 font-weight: normal;
99 padding: 0.1em 1em 0.1em 0.1em;
100}
101div.commit-subject {
102 font-weight: bold;
103 font-size: 110%;
104 margin: 1em 0em 1em;
105}
106div.commit-msg {
107 white-space: pre;
108 font-family: courier;
109 font-size: 100%;
110}
111.sha1 {
112 font-family: courier;
113 font-size: 90%;
114}
115.left {
116 text-align: left;
117}
118.right {
119 text-align: right;
120}
diff --git a/cgit.h b/cgit.h
index 268db53..a905e47 100644
--- a/cgit.h
+++ b/cgit.h
@@ -47,52 +47,53 @@ extern char *cgit_repo_owner;
47extern int cgit_query_has_symref; 47extern int cgit_query_has_symref;
48extern int cgit_query_has_sha1; 48extern int cgit_query_has_sha1;
49 49
50extern char *cgit_querystring; 50extern char *cgit_querystring;
51extern char *cgit_query_repo; 51extern char *cgit_query_repo;
52extern char *cgit_query_page; 52extern char *cgit_query_page;
53extern char *cgit_query_head; 53extern char *cgit_query_head;
54extern char *cgit_query_sha1; 54extern char *cgit_query_sha1;
55extern int cgit_query_ofs; 55extern int cgit_query_ofs;
56 56
57extern int htmlfd; 57extern int htmlfd;
58 58
59extern void cgit_global_config_cb(const char *name, const char *value); 59extern void cgit_global_config_cb(const char *name, const char *value);
60extern void cgit_repo_config_cb(const char *name, const char *value); 60extern void cgit_repo_config_cb(const char *name, const char *value);
61extern void cgit_querystring_cb(const char *name, const char *value); 61extern void cgit_querystring_cb(const char *name, const char *value);
62 62
63extern char *fmt(const char *format,...); 63extern char *fmt(const char *format,...);
64 64
65extern void html(const char *txt); 65extern void html(const char *txt);
66extern void htmlf(const char *format,...); 66extern void htmlf(const char *format,...);
67extern void html_txt(char *txt); 67extern void html_txt(char *txt);
68extern void html_attr(char *txt); 68extern void html_attr(char *txt);
69extern void html_link_open(char *url, char *title, char *class); 69extern void html_link_open(char *url, char *title, char *class);
70extern void html_link_close(void); 70extern void html_link_close(void);
71 71
72extern int cgit_read_config(const char *filename, configfn fn); 72extern int cgit_read_config(const char *filename, configfn fn);
73extern int cgit_parse_query(char *txt, configfn fn); 73extern int cgit_parse_query(char *txt, configfn fn);
74extern struct commitinfo *cgit_parse_commit(struct commit *commit); 74extern struct commitinfo *cgit_parse_commit(struct commit *commit);
75 75
76extern void cache_prepare(struct cacheitem *item); 76extern void cache_prepare(struct cacheitem *item);
77extern int cache_lock(struct cacheitem *item); 77extern int cache_lock(struct cacheitem *item);
78extern int cache_unlock(struct cacheitem *item); 78extern int cache_unlock(struct cacheitem *item);
79extern int cache_cancel_lock(struct cacheitem *item); 79extern int cache_cancel_lock(struct cacheitem *item);
80extern int cache_exist(struct cacheitem *item); 80extern int cache_exist(struct cacheitem *item);
81extern int cache_expired(struct cacheitem *item); 81extern int cache_expired(struct cacheitem *item);
82 82
83extern char *cgit_repourl(const char *reponame); 83extern char *cgit_repourl(const char *reponame);
84extern char *cgit_pageurl(const char *reponame, const char *pagename, 84extern char *cgit_pageurl(const char *reponame, const char *pagename,
85 const char *query); 85 const char *query);
86 86
87extern void cgit_print_error(char *msg); 87extern void cgit_print_error(char *msg);
88extern void cgit_print_docstart(char *title, struct cacheitem *item); 88extern void cgit_print_docstart(char *title, struct cacheitem *item);
89extern void cgit_print_docend(); 89extern void cgit_print_docend();
90extern void cgit_print_pageheader(char *title); 90extern void cgit_print_pageheader(char *title);
91 91
92extern void cgit_print_repolist(struct cacheitem *item); 92extern void cgit_print_repolist(struct cacheitem *item);
93extern void cgit_print_summary(); 93extern void cgit_print_summary();
94extern void cgit_print_log(const char *tip, int ofs, int cnt); 94extern void cgit_print_log(const char *tip, int ofs, int cnt);
95extern void cgit_print_view(char *hex); 95extern void cgit_print_view(const char *hex);
96extern void cgit_print_tree(const char *sha1); 96extern void cgit_print_tree(const char *hex);
97extern void cgit_print_commit(const char *hex);
97 98
98#endif /* CGIT_H */ 99#endif /* CGIT_H */
diff --git a/parsing.c b/parsing.c
index 6cab0e9..be471b5 100644
--- a/parsing.c
+++ b/parsing.c
@@ -105,55 +105,56 @@ int cgit_parse_query(char *txt, configfn fn)
105 return 0; 105 return 0;
106} 106}
107 107
108char *substr(const char *head, const char *tail) 108char *substr(const char *head, const char *tail)
109{ 109{
110 char *buf; 110 char *buf;
111 111
112 buf = xmalloc(tail - head + 1); 112 buf = xmalloc(tail - head + 1);
113 strncpy(buf, head, tail - head); 113 strncpy(buf, head, tail - head);
114 buf[tail - head] = '\0'; 114 buf[tail - head] = '\0';
115 return buf; 115 return buf;
116} 116}
117 117
118struct commitinfo *cgit_parse_commit(struct commit *commit) 118struct commitinfo *cgit_parse_commit(struct commit *commit)
119{ 119{
120 struct commitinfo *ret; 120 struct commitinfo *ret;
121 char *p = commit->buffer, *t = commit->buffer; 121 char *p = commit->buffer, *t = commit->buffer;
122 122
123 ret = xmalloc(sizeof(*ret)); 123 ret = xmalloc(sizeof(*ret));
124 ret->commit = commit; 124 ret->commit = commit;
125 125
126 if (strncmp(p, "tree ", 5)) 126 if (strncmp(p, "tree ", 5))
127 die("Bad commit: %s", sha1_to_hex(commit->object.sha1)); 127 die("Bad commit: %s", sha1_to_hex(commit->object.sha1));
128 else 128 else
129 p += 46; // "tree " + hex[40] + "\n" 129 p += 46; // "tree " + hex[40] + "\n"
130 130
131 while (!strncmp(p, "parent ", 7)) 131 while (!strncmp(p, "parent ", 7))
132 p += 48; // "parent " + hex[40] + "\n" 132 p += 48; // "parent " + hex[40] + "\n"
133 133
134 if (!strncmp(p, "author ", 7)) { 134 if (!strncmp(p, "author ", 7)) {
135 p += 7; 135 p += 7;
136 t = strchr(p, '<') - 1; 136 t = strchr(p, '<') - 1;
137 ret->author = substr(p, t); 137 ret->author = substr(p, t);
138 p = strchr(p, '\n') + 1; 138 p = strchr(p, '\n') + 1;
139 } 139 }
140 140
141 if (!strncmp(p, "committer ", 9)) { 141 if (!strncmp(p, "committer ", 9)) {
142 p += 9; 142 p += 9;
143 t = strchr(p, '<') - 1; 143 t = strchr(p, '<') - 1;
144 ret->committer = substr(p, t); 144 ret->committer = substr(p, t);
145 p = strchr(p, '\n') + 1; 145 p = strchr(p, '\n') + 1;
146 } 146 }
147 147
148 while (*p == '\n') 148 while (*p == '\n')
149 p = strchr(p, '\n') + 1; 149 p = strchr(p, '\n') + 1;
150 150
151 t = strchr(p, '\n'); 151 t = strchr(p, '\n');
152 ret->subject = substr(p, t); 152 ret->subject = substr(p, t);
153 p = t + 1;
153 154
154 while (*p == '\n') 155 while (*p == '\n')
155 p = strchr(p, '\n') + 1; 156 p = strchr(p, '\n') + 1;
156 ret->msg = p; 157 ret->msg = p;
157 158
158 return ret; 159 return ret;
159} 160}
diff --git a/ui-commit.c b/ui-commit.c
new file mode 100644
index 0000000..1c0e7e5
--- a/dev/null
+++ b/ui-commit.c
@@ -0,0 +1,80 @@
1#include "cgit.h"
2
3void cgit_print_date(unsigned long secs)
4{
5 char buf[32];
6 struct tm *time;
7
8 time = gmtime(&secs);
9 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", time);
10 html_txt(buf);
11
12}
13
14void cgit_print_commit(const char *hex)
15{
16 struct commit *commit;
17 struct commitinfo *info;
18 struct commit_list *p;
19 unsigned long size;
20 char type[20];
21 char *buf;
22
23 unsigned char sha1[20];
24
25 if (get_sha1(hex, sha1)) {
26 cgit_print_error(fmt("Bad object id: %s", hex));
27 return;
28 }
29
30 buf = read_sha1_file(sha1, type, &size);
31 if (!buf) {
32 cgit_print_error(fmt("Bad object reference: %s", hex));
33 return;
34 }
35
36 commit = lookup_commit(sha1);
37 if (!commit) {
38 cgit_print_error(fmt("Bad commit reference: %s", hex));
39 return;
40 }
41
42 commit->buffer = buf;
43 if (parse_commit_buffer(commit, buf, size)) {
44 cgit_print_error(fmt("Malformed commit buffer: %s", hex));
45 return;
46 }
47
48 info = cgit_parse_commit(commit);
49
50 html("<table class='commit-info'>\n");
51 html("<tr><th>author</th><td colspan='2'>");
52 html_txt(info->author);
53 html("</td></tr>\n");
54 html("<tr><th>committer</th><td>");
55 html_txt(info->committer);
56 html("</td><td class='right'>");
57 cgit_print_date(commit->date);
58 html("</td></tr>\n");
59 html("<tr><th>tree</th><td colspan='2' class='sha1'><a href='");
60 html_attr(cgit_pageurl(cgit_query_repo, "tree", fmt("id=%s", sha1_to_hex(commit->tree->object.sha1))));
61 htmlf("'>%s</a></td></tr>\n", sha1_to_hex(commit->tree->object.sha1));
62
63 for (p = commit->parents; p ; p = p->next) {
64 html("<tr><th>parent</th><td colspan='2' class='sha1'><a href='");
65 html_attr(cgit_pageurl(cgit_query_repo, "commit", fmt("id=%s", sha1_to_hex(p->item->object.sha1))));
66 htmlf("'>%s</a></td></tr>\n",
67 sha1_to_hex(p->item->object.sha1));
68 }
69 html("</table>\n");
70 html("<div class='commit-subject'>");
71 html_txt(info->subject);
72 html("</div>");
73 html("<div class='commit-msg'>");
74 html_txt(info->msg);
75 html("</div>");
76 free(info->author);
77 free(info->committer);
78 free(info->subject);
79 free(info);
80}
diff --git a/ui-log.c b/ui-log.c
index 31331ef..c52af79 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -1,97 +1,92 @@
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
11void print_commit(struct commit *commit) 11void print_commit(struct commit *commit)
12{ 12{
13 char buf[32]; 13 char buf[32];
14 struct commitinfo *info; 14 struct commitinfo *info;
15 struct tm *time; 15 struct tm *time;
16 16
17 info = cgit_parse_commit(commit); 17 info = cgit_parse_commit(commit);
18 time = gmtime(&commit->date); 18 time = gmtime(&commit->date);
19 html("<tr><td>"); 19 html("<tr><td>");
20 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", time); 20 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", time);
21 html_txt(buf); 21 html_txt(buf);
22 html("</td><td>"); 22 html("</td><td>");
23 char *qry = fmt("id=%s", sha1_to_hex(commit->object.sha1)); 23 char *qry = fmt("id=%s", sha1_to_hex(commit->object.sha1));
24 char *url = cgit_pageurl(cgit_query_repo, "view", qry); 24 char *url = cgit_pageurl(cgit_query_repo, "commit", qry);
25 html_link_open(url, NULL, NULL); 25 html_link_open(url, NULL, NULL);
26 html_txt(info->subject); 26 html_txt(info->subject);
27 html_link_close(); 27 html_link_close();
28 html("</td><td>"); 28 html("</td><td>");
29 html_txt(info->author); 29 html_txt(info->author);
30 html("</td><td><a href='");
31 html_attr(cgit_pageurl(cgit_query_repo, "tree",
32 fmt("id=%s",
33 sha1_to_hex(commit->tree->object.sha1))));
34 html("'>tree</a>");
35 html("</td></tr>\n"); 30 html("</td></tr>\n");
36 free(info->author); 31 free(info->author);
37 free(info->committer); 32 free(info->committer);
38 free(info->subject); 33 free(info->subject);
39 free(info); 34 free(info);
40} 35}
41 36
42 37
43void cgit_print_log(const char *tip, int ofs, int cnt) 38void cgit_print_log(const char *tip, int ofs, int cnt)
44{ 39{
45 struct rev_info rev; 40 struct rev_info rev;
46 struct commit *commit; 41 struct commit *commit;
47 const char *argv[2] = {NULL, tip}; 42 const char *argv[2] = {NULL, tip};
48 int i; 43 int i;
49 44
50 init_revisions(&rev, NULL); 45 init_revisions(&rev, NULL);
51 rev.abbrev = DEFAULT_ABBREV; 46 rev.abbrev = DEFAULT_ABBREV;
52 rev.commit_format = CMIT_FMT_DEFAULT; 47 rev.commit_format = CMIT_FMT_DEFAULT;
53 rev.verbose_header = 1; 48 rev.verbose_header = 1;
54 rev.show_root_diff = 0; 49 rev.show_root_diff = 0;
55 setup_revisions(2, argv, &rev, NULL); 50 setup_revisions(2, argv, &rev, NULL);
56 prepare_revision_walk(&rev); 51 prepare_revision_walk(&rev);
57 52
58 html("<h2>Log</h2>"); 53 html("<h2>Log</h2>");
59 html("<table class='list'>"); 54 html("<table class='list log'>");
60 html("<tr><th>Date</th><th>Message</th><th>Author</th><th>Link</th></tr>\n"); 55 html("<tr><th class='left'>Date</th><th class='left'>Message</th><th class='left'>Author</th></tr>\n");
61 56
62 if (ofs<0) 57 if (ofs<0)
63 ofs = 0; 58 ofs = 0;
64 59
65 for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) { 60 for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) {
66 free(commit->buffer); 61 free(commit->buffer);
67 commit->buffer = NULL; 62 commit->buffer = NULL;
68 free_commit_list(commit->parents); 63 free_commit_list(commit->parents);
69 commit->parents = NULL; 64 commit->parents = NULL;
70 } 65 }
71 66
72 for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) { 67 for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) {
73 print_commit(commit); 68 print_commit(commit);
74 free(commit->buffer); 69 free(commit->buffer);
75 commit->buffer = NULL; 70 commit->buffer = NULL;
76 free_commit_list(commit->parents); 71 free_commit_list(commit->parents);
77 commit->parents = NULL; 72 commit->parents = NULL;
78 } 73 }
79 html("</table>\n"); 74 html("</table>\n");
80 75
81 html("<div class='pager'>"); 76 html("<div class='pager'>");
82 if (ofs > 0) { 77 if (ofs > 0) {
83 html("&nbsp;<a href='"); 78 html("&nbsp;<a href='");
84 html(cgit_pageurl(cgit_query_repo, cgit_query_page, 79 html(cgit_pageurl(cgit_query_repo, cgit_query_page,
85 fmt("h=%s&ofs=%d", tip, ofs-cnt))); 80 fmt("h=%s&ofs=%d", tip, ofs-cnt)));
86 html("'>[prev]</a>&nbsp;"); 81 html("'>[prev]</a>&nbsp;");
87 } 82 }
88 83
89 if ((commit = get_revision(&rev)) != NULL) { 84 if ((commit = get_revision(&rev)) != NULL) {
90 html("&nbsp;<a href='"); 85 html("&nbsp;<a href='");
91 html(cgit_pageurl(cgit_query_repo, "log", 86 html(cgit_pageurl(cgit_query_repo, "log",
92 fmt("h=%s&ofs=%d", tip, ofs+cnt))); 87 fmt("h=%s&ofs=%d", tip, ofs+cnt)));
93 html("'>[next]</a>&nbsp;"); 88 html("'>[next]</a>&nbsp;");
94 } 89 }
95 html("</div>"); 90 html("</div>");
96} 91}
97 92
diff --git a/ui-tree.c b/ui-tree.c
index 84930cb..c4d75ab 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -17,54 +17,54 @@ static int print_entry(const unsigned char *sha1, const char *base,
17 char type[20]; 17 char type[20];
18 unsigned long size; 18 unsigned long size;
19 19
20 if (sha1_object_info(sha1, type, &size)) { 20 if (sha1_object_info(sha1, type, &size)) {
21 cgit_print_error(fmt("Bad object name: %s", 21 cgit_print_error(fmt("Bad object name: %s",
22 sha1_to_hex(sha1))); 22 sha1_to_hex(sha1)));
23 return 0; 23 return 0;
24 } 24 }
25 name = xstrdup(pathname); 25 name = xstrdup(pathname);
26 html("<tr><td>"); 26 html("<tr><td>");
27 if (S_ISDIR(mode)) { 27 if (S_ISDIR(mode)) {
28 html("<div class='ls-dir'><a href='"); 28 html("<div class='ls-dir'><a href='");
29 html_attr(cgit_pageurl(cgit_query_repo, "tree", 29 html_attr(cgit_pageurl(cgit_query_repo, "tree",
30 fmt("id=%s", sha1_to_hex(sha1)))); 30 fmt("id=%s", sha1_to_hex(sha1))));
31 } else { 31 } else {
32 html("<div class='ls-blob'><a href='"); 32 html("<div class='ls-blob'><a href='");
33 html_attr(cgit_pageurl(cgit_query_repo, "view", 33 html_attr(cgit_pageurl(cgit_query_repo, "view",
34 fmt("id=%s", sha1_to_hex(sha1)))); 34 fmt("id=%s", sha1_to_hex(sha1))));
35 } 35 }
36 html("'>"); 36 html("'>");
37 html_txt(name); 37 html_txt(name);
38 if (S_ISDIR(mode)) 38 if (S_ISDIR(mode))
39 html("/"); 39 html("/");
40 html("</a></div></td>"); 40 html("</a></div></td>");
41 htmlf("<td class='filesize'>%li</td>", size); 41 htmlf("<td class='filesize'>%li</td>", size);
42 htmlf("<td class='filemode'>%06o</td>", mode); 42 htmlf("<td class='filemode'>%06o</td>", mode);
43 html("</tr>\n"); 43 html("</tr>\n");
44 free(name); 44 free(name);
45 return 0; 45 return 0;
46} 46}
47 47
48void cgit_print_tree(const char *hex) 48void cgit_print_tree(const char *hex)
49{ 49{
50 struct tree *tree; 50 struct tree *tree;
51 unsigned char sha1[20]; 51 unsigned char sha1[20];
52 52
53 if (get_sha1_hex(hex, sha1)) { 53 if (get_sha1_hex(hex, sha1)) {
54 cgit_print_error(fmt("Invalid object id: %s", hex)); 54 cgit_print_error(fmt("Invalid object id: %s", hex));
55 return; 55 return;
56 } 56 }
57 tree = parse_tree_indirect(sha1); 57 tree = parse_tree_indirect(sha1);
58 if (!tree) { 58 if (!tree) {
59 cgit_print_error(fmt("Not a tree object: %s", hex)); 59 cgit_print_error(fmt("Not a tree object: %s", hex));
60 return; 60 return;
61 } 61 }
62 62
63 html("<h2>Tree content</h2>\n"); 63 html("<h2>Tree content</h2>\n");
64 html("<table class='list'>\n"); 64 html("<table class='list'>\n");
65 html("<tr><th>Name</th>"); 65 html("<tr><th class='left'>Name</th>");
66 html("<th class='filesize'>Size</th>"); 66 html("<th class='right'>Size</th>");
67 html("<th class='filemode'>Mode</th></tr>\n"); 67 html("<th class='right'>Mode</th></tr>\n");
68 read_tree_recursive(tree, "", 0, 1, NULL, print_entry); 68 read_tree_recursive(tree, "", 0, 1, NULL, print_entry);
69 html("</table>\n"); 69 html("</table>\n");
70} 70}
diff --git a/ui-view.c b/ui-view.c
index 9d13be1..b75ce9a 100644
--- a/ui-view.c
+++ b/ui-view.c
@@ -1,42 +1,42 @@
1/* ui-view.c: functions to output _any_ object, given it's sha1 1/* ui-view.c: functions to output _any_ object, given it's sha1
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
11void cgit_print_view(char *hex) 11void cgit_print_view(const char *hex)
12{ 12{
13 unsigned char sha1[20]; 13 unsigned char sha1[20];
14 char type[20]; 14 char type[20];
15 unsigned char *buf; 15 unsigned char *buf;
16 unsigned long size; 16 unsigned long size;
17 17
18 if (get_sha1_hex(hex, sha1)){ 18 if (get_sha1_hex(hex, sha1)){
19 cgit_print_error(fmt("Bad hex value: %s", hex)); 19 cgit_print_error(fmt("Bad hex value: %s", hex));
20 return; 20 return;
21 } 21 }
22 22
23 if (sha1_object_info(sha1, type, &size)){ 23 if (sha1_object_info(sha1, type, &size)){
24 cgit_print_error("Bad object name"); 24 cgit_print_error("Bad object name");
25 return; 25 return;
26 } 26 }
27 27
28 buf = read_sha1_file(sha1, type, &size); 28 buf = read_sha1_file(sha1, type, &size);
29 if (!buf) { 29 if (!buf) {
30 cgit_print_error("Error reading object"); 30 cgit_print_error("Error reading object");
31 return; 31 return;
32 } 32 }
33 33
34 buf[size] = '\0'; 34 buf[size] = '\0';
35 html("<h2>Object content</h2>\n"); 35 html("<h2>Object content</h2>\n");
36 html("<table class='list'>\n"); 36 html("<table class='list'>\n");
37 htmlf("<tr><th>%s %s, %li bytes</th></tr>\n", type, hex, size); 37 htmlf("<tr><th>%s %s, %li bytes</th></tr>\n", type, hex, size);
38 html("<tr><td class='blob'>\n"); 38 html("<tr><td class='blob'>\n");
39 html_txt(buf); 39 html_txt(buf);
40 html("\n</td></tr>\n"); 40 html("\n</td></tr>\n");
41 html("</table>\n"); 41 html("</table>\n");
42} 42}