summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2006-12-28 01:01:49 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2006-12-28 01:01:49 (UTC)
commite39d738c39d37cdef115c145027f3eec85a62272 (patch) (unidiff)
treebe60a07674a0d118d42f572a35b62ada9529a6bd
parent27cd3b2a700e1cc46cd0393ddea48c07b62ee3a6 (diff)
downloadcgit-e39d738c39d37cdef115c145027f3eec85a62272.zip
cgit-e39d738c39d37cdef115c145027f3eec85a62272.tar.gz
cgit-e39d738c39d37cdef115c145027f3eec85a62272.tar.bz2
Add generic support for search box in page header
This adds the ability to show a search box in any pageheader with correct href and hidden form data, but does not enable the box on any pages. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c4
-rw-r--r--cgit.css5
-rw-r--r--cgit.h4
-rw-r--r--html.c10
-rw-r--r--shared.c3
-rw-r--r--ui-repolist.c2
-rw-r--r--ui-shared.c28
7 files changed, 51 insertions, 5 deletions
diff --git a/cgit.c b/cgit.c
index ac43441..277b849 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,160 +1,160 @@
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, 0);
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, 0);
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")) { 35 } else if (!strcmp(cgit_query_page, "commit")) {
36 cgit_print_commit(cgit_query_sha1); 36 cgit_print_commit(cgit_query_sha1);
37 } else if (!strcmp(cgit_query_page, "view")) { 37 } else if (!strcmp(cgit_query_page, "view")) {
38 cgit_print_view(cgit_query_sha1); 38 cgit_print_view(cgit_query_sha1);
39 } else if (!strcmp(cgit_query_page, "diff")) { 39 } else if (!strcmp(cgit_query_page, "diff")) {
40 cgit_print_diff(cgit_query_sha1, cgit_query_sha2); 40 cgit_print_diff(cgit_query_sha1, cgit_query_sha2);
41 } 41 }
42 cgit_print_docend(); 42 cgit_print_docend();
43} 43}
44 44
45static void cgit_fill_cache(struct cacheitem *item) 45static void cgit_fill_cache(struct cacheitem *item)
46{ 46{
47 static char buf[PATH_MAX]; 47 static char buf[PATH_MAX];
48 48
49 getcwd(buf, sizeof(buf)); 49 getcwd(buf, sizeof(buf));
50 htmlfd = item->fd; 50 htmlfd = item->fd;
51 item->st.st_mtime = time(NULL); 51 item->st.st_mtime = time(NULL);
52 if (cgit_query_repo) 52 if (cgit_query_repo)
53 cgit_print_repo_page(item); 53 cgit_print_repo_page(item);
54 else 54 else
55 cgit_print_repolist(item); 55 cgit_print_repolist(item);
56 chdir(buf); 56 chdir(buf);
57} 57}
58 58
59static void cgit_check_cache(struct cacheitem *item) 59static void cgit_check_cache(struct cacheitem *item)
60{ 60{
61 int i = 0; 61 int i = 0;
62 62
63 cache_prepare(item); 63 cache_prepare(item);
64 top: 64 top:
65 if (++i > cgit_max_lock_attempts) { 65 if (++i > cgit_max_lock_attempts) {
66 die("cgit_refresh_cache: unable to lock %s: %s", 66 die("cgit_refresh_cache: unable to lock %s: %s",
67 item->name, strerror(errno)); 67 item->name, strerror(errno));
68 } 68 }
69 if (!cache_exist(item)) { 69 if (!cache_exist(item)) {
70 if (!cache_lock(item)) { 70 if (!cache_lock(item)) {
71 sleep(1); 71 sleep(1);
72 goto top; 72 goto top;
73 } 73 }
74 if (!cache_exist(item)) { 74 if (!cache_exist(item)) {
75 cgit_fill_cache(item); 75 cgit_fill_cache(item);
76 cache_unlock(item); 76 cache_unlock(item);
77 } else { 77 } else {
78 cache_cancel_lock(item); 78 cache_cancel_lock(item);
79 } 79 }
80 } else if (cache_expired(item) && cache_lock(item)) { 80 } else if (cache_expired(item) && cache_lock(item)) {
81 if (cache_expired(item)) { 81 if (cache_expired(item)) {
82 cgit_fill_cache(item); 82 cgit_fill_cache(item);
83 cache_unlock(item); 83 cache_unlock(item);
84 } else { 84 } else {
85 cache_cancel_lock(item); 85 cache_cancel_lock(item);
86 } 86 }
87 } 87 }
88} 88}
89 89
90static void cgit_print_cache(struct cacheitem *item) 90static void cgit_print_cache(struct cacheitem *item)
91{ 91{
92 static char buf[4096]; 92 static char buf[4096];
93 ssize_t i; 93 ssize_t i;
94 94
95 int fd = open(item->name, O_RDONLY); 95 int fd = open(item->name, O_RDONLY);
96 if (fd<0) 96 if (fd<0)
97 die("Unable to open cached file %s", item->name); 97 die("Unable to open cached file %s", item->name);
98 98
99 while((i=read(fd, buf, sizeof(buf))) > 0) 99 while((i=read(fd, buf, sizeof(buf))) > 0)
100 write(STDOUT_FILENO, buf, i); 100 write(STDOUT_FILENO, buf, i);
101 101
102 close(fd); 102 close(fd);
103} 103}
104 104
105static void cgit_parse_args(int argc, const char **argv) 105static void cgit_parse_args(int argc, const char **argv)
106{ 106{
107 int i; 107 int i;
108 108
109 for (i = 1; i < argc; i++) { 109 for (i = 1; i < argc; i++) {
110 if (!strncmp(argv[i], "--root=", 7)) { 110 if (!strncmp(argv[i], "--root=", 7)) {
111 cgit_root = xstrdup(argv[i]+7); 111 cgit_root = xstrdup(argv[i]+7);
112 } 112 }
113 if (!strncmp(argv[i], "--cache=", 8)) { 113 if (!strncmp(argv[i], "--cache=", 8)) {
114 cgit_cache_root = xstrdup(argv[i]+8); 114 cgit_cache_root = xstrdup(argv[i]+8);
115 } 115 }
116 if (!strcmp(argv[i], "--nocache")) { 116 if (!strcmp(argv[i], "--nocache")) {
117 cgit_nocache = 1; 117 cgit_nocache = 1;
118 } 118 }
119 if (!strncmp(argv[i], "--query=", 8)) { 119 if (!strncmp(argv[i], "--query=", 8)) {
120 cgit_querystring = xstrdup(argv[i]+8); 120 cgit_querystring = xstrdup(argv[i]+8);
121 } 121 }
122 if (!strncmp(argv[i], "--repo=", 7)) { 122 if (!strncmp(argv[i], "--repo=", 7)) {
123 cgit_query_repo = xstrdup(argv[i]+7); 123 cgit_query_repo = xstrdup(argv[i]+7);
124 } 124 }
125 if (!strncmp(argv[i], "--page=", 7)) { 125 if (!strncmp(argv[i], "--page=", 7)) {
126 cgit_query_page = xstrdup(argv[i]+7); 126 cgit_query_page = xstrdup(argv[i]+7);
127 } 127 }
128 if (!strncmp(argv[i], "--head=", 7)) { 128 if (!strncmp(argv[i], "--head=", 7)) {
129 cgit_query_head = xstrdup(argv[i]+7); 129 cgit_query_head = xstrdup(argv[i]+7);
130 cgit_query_has_symref = 1; 130 cgit_query_has_symref = 1;
131 } 131 }
132 if (!strncmp(argv[i], "--sha1=", 7)) { 132 if (!strncmp(argv[i], "--sha1=", 7)) {
133 cgit_query_sha1 = xstrdup(argv[i]+7); 133 cgit_query_sha1 = xstrdup(argv[i]+7);
134 cgit_query_has_sha1 = 1; 134 cgit_query_has_sha1 = 1;
135 } 135 }
136 if (!strncmp(argv[i], "--ofs=", 6)) { 136 if (!strncmp(argv[i], "--ofs=", 6)) {
137 cgit_query_ofs = atoi(argv[i]+6); 137 cgit_query_ofs = atoi(argv[i]+6);
138 } 138 }
139 } 139 }
140} 140}
141 141
142int main(int argc, const char **argv) 142int main(int argc, const char **argv)
143{ 143{
144 struct cacheitem item; 144 struct cacheitem item;
145 145
146 cgit_read_config("/etc/cgitrc", cgit_global_config_cb); 146 cgit_read_config("/etc/cgitrc", cgit_global_config_cb);
147 if (getenv("QUERY_STRING")) 147 if (getenv("QUERY_STRING"))
148 cgit_querystring = xstrdup(getenv("QUERY_STRING")); 148 cgit_querystring = xstrdup(getenv("QUERY_STRING"));
149 cgit_parse_args(argc, argv); 149 cgit_parse_args(argc, argv);
150 cgit_parse_query(cgit_querystring, cgit_querystring_cb); 150 cgit_parse_query(cgit_querystring, cgit_querystring_cb);
151 151
152 if (cgit_nocache) { 152 if (cgit_nocache) {
153 item.fd = STDOUT_FILENO; 153 item.fd = STDOUT_FILENO;
154 cgit_fill_cache(&item); 154 cgit_fill_cache(&item);
155 } else { 155 } else {
156 cgit_check_cache(&item); 156 cgit_check_cache(&item);
157 cgit_print_cache(&item); 157 cgit_print_cache(&item);
158 } 158 }
159 return 0; 159 return 0;
160} 160}
diff --git a/cgit.css b/cgit.css
index 459dca7..9112bfe 100644
--- a/cgit.css
+++ b/cgit.css
@@ -1,191 +1,196 @@
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 1em; 6 margin: 0.5em 1em;
7} 7}
8 8
9 9
10h2 { 10h2 {
11 font-size: 100%; 11 font-size: 100%;
12 font-weight: bold; 12 font-weight: bold;
13 margin-bottom: 0.1em; 13 margin-bottom: 0.1em;
14} 14}
15 15
16a { 16a {
17 color: blue; 17 color: blue;
18 text-decoration: none; 18 text-decoration: none;
19} 19}
20 20
21a:hover { 21a:hover {
22 text-decoration: underline; 22 text-decoration: underline;
23} 23}
24 24
25table.list { 25table.list {
26 border: solid 1px black; 26 border: solid 1px black;
27 border-collapse: collapse; 27 border-collapse: collapse;
28 border: solid 1px #aaa; 28 border: solid 1px #aaa;
29} 29}
30table.list tr { 30table.list tr {
31 background: white; 31 background: white;
32} 32}
33table.list tr:hover { 33table.list tr:hover {
34 background: #eeb; 34 background: #eeb;
35} 35}
36table.list th { 36table.list th {
37 font-weight: normal; 37 font-weight: normal;
38 background: #ddd; 38 background: #ddd;
39 border-bottom: solid 1px #aaa; 39 border-bottom: solid 1px #aaa;
40 padding: 0.1em 0.5em 0.1em 0.5em; 40 padding: 0.1em 0.5em 0.1em 0.5em;
41 vertical-align: baseline; 41 vertical-align: baseline;
42} 42}
43table.list td { 43table.list td {
44 border: none; 44 border: none;
45 padding: 0.1em 0.5em 0.1em 0.5em; 45 padding: 0.1em 0.5em 0.1em 0.5em;
46} 46}
47img { 47img {
48 border: none; 48 border: none;
49} 49}
50 50
51 51
52div#header { 52div#header {
53 background-color: #ddd; 53 background-color: #ddd;
54 padding: 0.25em 0.25em 0.25em 0.5em; 54 padding: 0.25em 0.25em 0.25em 0.5em;
55 font-size: 150%; 55 font-size: 150%;
56 font-weight: bold; 56 font-weight: bold;
57 border: solid 1px #aaa; 57 border: solid 1px #aaa;
58 vertical-align: middle; 58 vertical-align: middle;
59 margin-bottom: 2em; 59 margin-bottom: 2em;
60} 60}
61div#header img#logo { 61div#header img#logo {
62 float: right; 62 float: right;
63} 63}
64
65div#header input {
66 float: right;
67 margin: 0.25em 1em;
68}
64div#header a { 69div#header a {
65 color: black; 70 color: black;
66} 71}
67 72
68div#content { 73div#content {
69 margin: 0.5em 0.5em; 74 margin: 0.5em 0.5em;
70} 75}
71 76
72div#blob { 77div#blob {
73 border: solid 1px black; 78 border: solid 1px black;
74} 79}
75 80
76div.error { 81div.error {
77 color: red; 82 color: red;
78 font-weight: bold; 83 font-weight: bold;
79 margin: 1em 2em; 84 margin: 1em 2em;
80} 85}
81div.ls-blob, div.ls-dir { 86div.ls-blob, div.ls-dir {
82 font-family: monospace; 87 font-family: monospace;
83} 88}
84div.ls-dir a { 89div.ls-dir a {
85 font-weight: bold; 90 font-weight: bold;
86} 91}
87th.filesize, td.filesize { 92th.filesize, td.filesize {
88 text-align: right; 93 text-align: right;
89} 94}
90td.filesize { 95td.filesize {
91 font-family: monospace; 96 font-family: monospace;
92} 97}
93td.filemode { 98td.filemode {
94 font-family: monospace; 99 font-family: monospace;
95} 100}
96 101
97td.blob { 102td.blob {
98 white-space: pre; 103 white-space: pre;
99 font-family: monospace; 104 font-family: monospace;
100 background-color: white; 105 background-color: white;
101} 106}
102 107
103table.nowrap td { 108table.nowrap td {
104 white-space: nowrap; 109 white-space: nowrap;
105} 110}
106 111
107table.commit-info { 112table.commit-info {
108 border-collapse: collapse; 113 border-collapse: collapse;
109 margin-top: 1.5em; 114 margin-top: 1.5em;
110} 115}
111table.commit-info th { 116table.commit-info th {
112 text-align: left; 117 text-align: left;
113 font-weight: normal; 118 font-weight: normal;
114 padding: 0.1em 1em 0.1em 0.1em; 119 padding: 0.1em 1em 0.1em 0.1em;
115} 120}
116table.commit-info td { 121table.commit-info td {
117 font-weight: normal; 122 font-weight: normal;
118 padding: 0.1em 1em 0.1em 0.1em; 123 padding: 0.1em 1em 0.1em 0.1em;
119} 124}
120div.commit-subject { 125div.commit-subject {
121 font-weight: bold; 126 font-weight: bold;
122 font-size: 125%; 127 font-size: 125%;
123 margin: 1.5em 0em 0.5em 0em; 128 margin: 1.5em 0em 0.5em 0em;
124 padding: 0em; 129 padding: 0em;
125} 130}
126div.commit-msg { 131div.commit-msg {
127 white-space: pre; 132 white-space: pre;
128 font-family: monospace; 133 font-family: monospace;
129} 134}
130table.diffstat { 135table.diffstat {
131 border-collapse: collapse; 136 border-collapse: collapse;
132 margin-top: 1.5em; 137 margin-top: 1.5em;
133} 138}
134table.diffstat th { 139table.diffstat th {
135 font-weight: normal; 140 font-weight: normal;
136 text-align: left; 141 text-align: left;
137 text-decoration: underline; 142 text-decoration: underline;
138 padding: 0.1em 1em 0.1em 0.1em; 143 padding: 0.1em 1em 0.1em 0.1em;
139 font-size: 100%; 144 font-size: 100%;
140} 145}
141table.diffstat td { 146table.diffstat td {
142 padding: 0.1em 1em 0.1em 0.1em; 147 padding: 0.1em 1em 0.1em 0.1em;
143 font-size: 100%; 148 font-size: 100%;
144} 149}
145table.diffstat td span.modechange { 150table.diffstat td span.modechange {
146 padding-left: 1em; 151 padding-left: 1em;
147 color: red; 152 color: red;
148} 153}
149table.diffstat td.add a { 154table.diffstat td.add a {
150 color: green; 155 color: green;
151} 156}
152table.diffstat td.del a { 157table.diffstat td.del a {
153 color: red; 158 color: red;
154} 159}
155table.diffstat td.upd a { 160table.diffstat td.upd a {
156 color: blue; 161 color: blue;
157} 162}
158table.diffstat td.summary { 163table.diffstat td.summary {
159 /* border-top: solid 1px black; */ 164 /* border-top: solid 1px black; */
160 color: #888; 165 color: #888;
161 padding-top: 0.5em; 166 padding-top: 0.5em;
162} 167}
163 168
164table.diff td { 169table.diff td {
165 border: solid 1px black; 170 border: solid 1px black;
166 font-family: monospace; 171 font-family: monospace;
167 white-space: pre; 172 white-space: pre;
168} 173}
169 174
170table.diff td div.hunk { 175table.diff td div.hunk {
171 background: #ccc; 176 background: #ccc;
172} 177}
173 178
174table.diff td div.add { 179table.diff td div.add {
175 color: green; 180 color: green;
176} 181}
177 182
178table.diff td div.del { 183table.diff td div.del {
179 color: red; 184 color: red;
180} 185}
181 186
182.sha1 { 187.sha1 {
183 font-family: courier; 188 font-family: courier;
184 font-size: 90%; 189 font-size: 90%;
185} 190}
186.left { 191.left {
187 text-align: left; 192 text-align: left;
188} 193}
189.right { 194.right {
190 text-align: right; 195 text-align: right;
191} 196}
diff --git a/cgit.h b/cgit.h
index 362b435..e114a50 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,111 +1,113 @@
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
18struct commitinfo { 18struct commitinfo {
19 struct commit *commit; 19 struct commit *commit;
20 char *author; 20 char *author;
21 char *author_email; 21 char *author_email;
22 unsigned long author_date; 22 unsigned long author_date;
23 char *committer; 23 char *committer;
24 char *committer_email; 24 char *committer_email;
25 unsigned long committer_date; 25 unsigned long committer_date;
26 char *subject; 26 char *subject;
27 char *msg; 27 char *msg;
28}; 28};
29 29
30extern const char cgit_version[]; 30extern const char cgit_version[];
31 31
32extern char *cgit_root; 32extern char *cgit_root;
33extern char *cgit_root_title; 33extern char *cgit_root_title;
34extern char *cgit_css; 34extern char *cgit_css;
35extern char *cgit_logo; 35extern char *cgit_logo;
36extern char *cgit_logo_link; 36extern char *cgit_logo_link;
37extern char *cgit_virtual_root; 37extern char *cgit_virtual_root;
38extern char *cgit_cache_root; 38extern char *cgit_cache_root;
39 39
40extern int cgit_nocache; 40extern int cgit_nocache;
41extern int cgit_max_lock_attempts; 41extern int cgit_max_lock_attempts;
42extern int cgit_cache_root_ttl; 42extern int cgit_cache_root_ttl;
43extern int cgit_cache_repo_ttl; 43extern int cgit_cache_repo_ttl;
44extern int cgit_cache_dynamic_ttl; 44extern int cgit_cache_dynamic_ttl;
45extern int cgit_cache_static_ttl; 45extern int cgit_cache_static_ttl;
46extern int cgit_cache_max_create_time; 46extern int cgit_cache_max_create_time;
47 47
48extern char *cgit_repo_name; 48extern char *cgit_repo_name;
49extern char *cgit_repo_desc; 49extern char *cgit_repo_desc;
50extern char *cgit_repo_owner; 50extern char *cgit_repo_owner;
51 51
52extern int cgit_query_has_symref; 52extern int cgit_query_has_symref;
53extern int cgit_query_has_sha1; 53extern int cgit_query_has_sha1;
54 54
55extern char *cgit_querystring; 55extern char *cgit_querystring;
56extern char *cgit_query_repo; 56extern char *cgit_query_repo;
57extern char *cgit_query_page; 57extern char *cgit_query_page;
58extern char *cgit_query_search;
58extern char *cgit_query_head; 59extern char *cgit_query_head;
59extern char *cgit_query_sha1; 60extern char *cgit_query_sha1;
60extern char *cgit_query_sha2; 61extern char *cgit_query_sha2;
61extern int cgit_query_ofs; 62extern int cgit_query_ofs;
62 63
63extern int htmlfd; 64extern int htmlfd;
64 65
65extern void cgit_global_config_cb(const char *name, const char *value); 66extern void cgit_global_config_cb(const char *name, const char *value);
66extern void cgit_repo_config_cb(const char *name, const char *value); 67extern void cgit_repo_config_cb(const char *name, const char *value);
67extern void cgit_querystring_cb(const char *name, const char *value); 68extern void cgit_querystring_cb(const char *name, const char *value);
68 69
69extern void *cgit_free_commitinfo(struct commitinfo *info); 70extern void *cgit_free_commitinfo(struct commitinfo *info);
70 71
71extern char *fmt(const char *format,...); 72extern char *fmt(const char *format,...);
72 73
73extern void html(const char *txt); 74extern void html(const char *txt);
74extern void htmlf(const char *format,...); 75extern void htmlf(const char *format,...);
75extern void html_txt(char *txt); 76extern void html_txt(char *txt);
76extern void html_ntxt(int len, char *txt); 77extern void html_ntxt(int len, char *txt);
77extern void html_attr(char *txt); 78extern void html_attr(char *txt);
79extern void html_hidden(char *name, char *value);
78extern void html_link_open(char *url, char *title, char *class); 80extern void html_link_open(char *url, char *title, char *class);
79extern void html_link_close(void); 81extern void html_link_close(void);
80extern void html_filemode(unsigned short mode); 82extern void html_filemode(unsigned short mode);
81 83
82extern int cgit_read_config(const char *filename, configfn fn); 84extern int cgit_read_config(const char *filename, configfn fn);
83extern int cgit_parse_query(char *txt, configfn fn); 85extern int cgit_parse_query(char *txt, configfn fn);
84extern struct commitinfo *cgit_parse_commit(struct commit *commit); 86extern struct commitinfo *cgit_parse_commit(struct commit *commit);
85 87
86extern void cache_prepare(struct cacheitem *item); 88extern void cache_prepare(struct cacheitem *item);
87extern int cache_lock(struct cacheitem *item); 89extern int cache_lock(struct cacheitem *item);
88extern int cache_unlock(struct cacheitem *item); 90extern int cache_unlock(struct cacheitem *item);
89extern int cache_cancel_lock(struct cacheitem *item); 91extern int cache_cancel_lock(struct cacheitem *item);
90extern int cache_exist(struct cacheitem *item); 92extern int cache_exist(struct cacheitem *item);
91extern int cache_expired(struct cacheitem *item); 93extern int cache_expired(struct cacheitem *item);
92 94
93extern char *cgit_repourl(const char *reponame); 95extern char *cgit_repourl(const char *reponame);
94extern char *cgit_pageurl(const char *reponame, const char *pagename, 96extern char *cgit_pageurl(const char *reponame, const char *pagename,
95 const char *query); 97 const char *query);
96 98
97extern void cgit_print_error(char *msg); 99extern void cgit_print_error(char *msg);
98extern void cgit_print_date(unsigned long secs); 100extern void cgit_print_date(unsigned long secs);
99extern void cgit_print_docstart(char *title, struct cacheitem *item); 101extern void cgit_print_docstart(char *title, struct cacheitem *item);
100extern void cgit_print_docend(); 102extern void cgit_print_docend();
101extern void cgit_print_pageheader(char *title); 103extern void cgit_print_pageheader(char *title, int show_search);
102 104
103extern void cgit_print_repolist(struct cacheitem *item); 105extern void cgit_print_repolist(struct cacheitem *item);
104extern void cgit_print_summary(); 106extern void cgit_print_summary();
105extern void cgit_print_log(const char *tip, int ofs, int cnt); 107extern void cgit_print_log(const char *tip, int ofs, int cnt);
106extern void cgit_print_view(const char *hex); 108extern void cgit_print_view(const char *hex);
107extern void cgit_print_tree(const char *hex); 109extern void cgit_print_tree(const char *hex);
108extern void cgit_print_commit(const char *hex); 110extern void cgit_print_commit(const char *hex);
109extern void cgit_print_diff(const char *old_hex, const char *new_hex); 111extern void cgit_print_diff(const char *old_hex, const char *new_hex);
110 112
111#endif /* CGIT_H */ 113#endif /* CGIT_H */
diff --git a/html.c b/html.c
index 3a5d28d..c0b2ed4 100644
--- a/html.c
+++ b/html.c
@@ -1,157 +1,167 @@
1/* html.c: helper functions for html output 1/* html.c: helper functions for html 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
11char *fmt(const char *format, ...) 11char *fmt(const char *format, ...)
12{ 12{
13 static char buf[8][1024]; 13 static char buf[8][1024];
14 static int bufidx; 14 static int bufidx;
15 int len; 15 int len;
16 va_list args; 16 va_list args;
17 17
18 bufidx++; 18 bufidx++;
19 bufidx &= 7; 19 bufidx &= 7;
20 20
21 va_start(args, format); 21 va_start(args, format);
22 len = vsnprintf(buf[bufidx], sizeof(buf[bufidx]), format, args); 22 len = vsnprintf(buf[bufidx], sizeof(buf[bufidx]), format, args);
23 va_end(args); 23 va_end(args);
24 if (len>sizeof(buf[bufidx])) 24 if (len>sizeof(buf[bufidx]))
25 die("[html.c] string truncated: %s", format); 25 die("[html.c] string truncated: %s", format);
26 return buf[bufidx]; 26 return buf[bufidx];
27} 27}
28 28
29void html(const char *txt) 29void html(const char *txt)
30{ 30{
31 write(htmlfd, txt, strlen(txt)); 31 write(htmlfd, txt, strlen(txt));
32} 32}
33 33
34void htmlf(const char *format, ...) 34void htmlf(const char *format, ...)
35{ 35{
36 static char buf[65536]; 36 static char buf[65536];
37 va_list args; 37 va_list args;
38 38
39 va_start(args, format); 39 va_start(args, format);
40 vsnprintf(buf, sizeof(buf), format, args); 40 vsnprintf(buf, sizeof(buf), format, args);
41 va_end(args); 41 va_end(args);
42 html(buf); 42 html(buf);
43} 43}
44 44
45void html_txt(char *txt) 45void html_txt(char *txt)
46{ 46{
47 char *t = txt; 47 char *t = txt;
48 while(t && *t){ 48 while(t && *t){
49 int c = *t; 49 int c = *t;
50 if (c=='<' || c=='>' || c=='&') { 50 if (c=='<' || c=='>' || c=='&') {
51 *t = '\0'; 51 *t = '\0';
52 html(txt); 52 html(txt);
53 *t = c; 53 *t = c;
54 if (c=='>') 54 if (c=='>')
55 html("&gt;"); 55 html("&gt;");
56 else if (c=='<') 56 else if (c=='<')
57 html("&lt;"); 57 html("&lt;");
58 else if (c=='&') 58 else if (c=='&')
59 html("&amp;"); 59 html("&amp;");
60 txt = t+1; 60 txt = t+1;
61 } 61 }
62 t++; 62 t++;
63 } 63 }
64 if (t!=txt) 64 if (t!=txt)
65 html(txt); 65 html(txt);
66} 66}
67 67
68void html_ntxt(int len, char *txt) 68void html_ntxt(int len, char *txt)
69{ 69{
70 char *t = txt; 70 char *t = txt;
71 while(t && *t && len--){ 71 while(t && *t && len--){
72 int c = *t; 72 int c = *t;
73 if (c=='<' || c=='>' || c=='&') { 73 if (c=='<' || c=='>' || c=='&') {
74 *t = '\0'; 74 *t = '\0';
75 html(txt); 75 html(txt);
76 *t = c; 76 *t = c;
77 if (c=='>') 77 if (c=='>')
78 html("&gt;"); 78 html("&gt;");
79 else if (c=='<') 79 else if (c=='<')
80 html("&lt;"); 80 html("&lt;");
81 else if (c=='&') 81 else if (c=='&')
82 html("&amp;"); 82 html("&amp;");
83 txt = t+1; 83 txt = t+1;
84 } 84 }
85 t++; 85 t++;
86 } 86 }
87 if (t!=txt) { 87 if (t!=txt) {
88 char c = *t; 88 char c = *t;
89 *t = '\0'; 89 *t = '\0';
90 html(txt); 90 html(txt);
91 *t = c; 91 *t = c;
92 } 92 }
93 if (len<0) 93 if (len<0)
94 html("..."); 94 html("...");
95} 95}
96 96
97void html_attr(char *txt) 97void html_attr(char *txt)
98{ 98{
99 char *t = txt; 99 char *t = txt;
100 while(t && *t){ 100 while(t && *t){
101 int c = *t; 101 int c = *t;
102 if (c=='<' || c=='>' || c=='\'') { 102 if (c=='<' || c=='>' || c=='\'') {
103 *t = '\0'; 103 *t = '\0';
104 html(txt); 104 html(txt);
105 *t = c; 105 *t = c;
106 if (c=='>') 106 if (c=='>')
107 html("&gt;"); 107 html("&gt;");
108 else if (c=='<') 108 else if (c=='<')
109 html("&lt;"); 109 html("&lt;");
110 else if (c=='\'') 110 else if (c=='\'')
111 html("&quote;"); 111 html("&quote;");
112 txt = t+1; 112 txt = t+1;
113 } 113 }
114 t++; 114 t++;
115 } 115 }
116 if (t!=txt) 116 if (t!=txt)
117 html(txt); 117 html(txt);
118} 118}
119 119
120void html_hidden(char *name, char *value)
121{
122 html("<input type='hidden' name='");
123 html_attr(name);
124 html("' value='");
125 html_attr(value);
126 html("'/>");
127}
128
120void html_link_open(char *url, char *title, char *class) 129void html_link_open(char *url, char *title, char *class)
121{ 130{
122 html("<a href='"); 131 html("<a href='");
123 html_attr(url); 132 html_attr(url);
124 if (title) { 133 if (title) {
125 html("' title='"); 134 html("' title='");
126 html_attr(title); 135 html_attr(title);
127 } 136 }
128 if (class) { 137 if (class) {
129 html("' class='"); 138 html("' class='");
130 html_attr(class); 139 html_attr(class);
131 } 140 }
132 html("'>"); 141 html("'>");
133} 142}
134 143
135void html_link_close(void) 144void html_link_close(void)
136{ 145{
137 html("</a>"); 146 html("</a>");
138} 147}
139 148
140void html_fileperm(unsigned short mode) 149void html_fileperm(unsigned short mode)
141{ 150{
142 htmlf("%c%c%c", (mode & 4 ? 'r' : '-'), 151 htmlf("%c%c%c", (mode & 4 ? 'r' : '-'),
143 (mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-')); 152 (mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-'));
144} 153}
145 154
146void html_filemode(unsigned short mode) 155void html_filemode(unsigned short mode)
147{ 156{
148 if (S_ISDIR(mode)) 157 if (S_ISDIR(mode))
149 html("d"); 158 html("d");
150 else if (S_ISLNK(mode)) 159 else if (S_ISLNK(mode))
151 html("l"); 160 html("l");
152 else 161 else
153 html("-"); 162 html("-");
154 html_fileperm(mode >> 6); 163 html_fileperm(mode >> 6);
155 html_fileperm(mode >> 3); 164 html_fileperm(mode >> 3);
156 html_fileperm(mode); 165 html_fileperm(mode);
157} 166}
167
diff --git a/shared.c b/shared.c
index 18b795b..7def51a 100644
--- a/shared.c
+++ b/shared.c
@@ -1,112 +1,115 @@
1/* shared.c: global vars + some callback functions 1/* shared.c: global vars + some callback functions
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10 10
11char *cgit_root = "/usr/src/git"; 11char *cgit_root = "/usr/src/git";
12char *cgit_root_title = "Git repository browser"; 12char *cgit_root_title = "Git repository browser";
13char *cgit_css = "/cgit.css"; 13char *cgit_css = "/cgit.css";
14char *cgit_logo = "/git-logo.png"; 14char *cgit_logo = "/git-logo.png";
15char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/"; 15char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/";
16char *cgit_virtual_root = NULL; 16char *cgit_virtual_root = NULL;
17 17
18char *cgit_cache_root = "/var/cache/cgit"; 18char *cgit_cache_root = "/var/cache/cgit";
19 19
20int cgit_nocache = 0; 20int cgit_nocache = 0;
21int cgit_max_lock_attempts = 5; 21int cgit_max_lock_attempts = 5;
22int cgit_cache_root_ttl = 5; 22int cgit_cache_root_ttl = 5;
23int cgit_cache_repo_ttl = 5; 23int cgit_cache_repo_ttl = 5;
24int cgit_cache_dynamic_ttl = 5; 24int cgit_cache_dynamic_ttl = 5;
25int cgit_cache_static_ttl = -1; 25int cgit_cache_static_ttl = -1;
26int cgit_cache_max_create_time = 5; 26int cgit_cache_max_create_time = 5;
27 27
28char *cgit_repo_name = NULL; 28char *cgit_repo_name = NULL;
29char *cgit_repo_desc = NULL; 29char *cgit_repo_desc = NULL;
30char *cgit_repo_owner = NULL; 30char *cgit_repo_owner = NULL;
31 31
32int cgit_query_has_symref = 0; 32int cgit_query_has_symref = 0;
33int cgit_query_has_sha1 = 0; 33int cgit_query_has_sha1 = 0;
34 34
35char *cgit_querystring = NULL; 35char *cgit_querystring = NULL;
36char *cgit_query_repo = NULL; 36char *cgit_query_repo = NULL;
37char *cgit_query_page = NULL; 37char *cgit_query_page = NULL;
38char *cgit_query_head = NULL; 38char *cgit_query_head = NULL;
39char *cgit_query_search = NULL;
39char *cgit_query_sha1 = NULL; 40char *cgit_query_sha1 = NULL;
40char *cgit_query_sha2 = NULL; 41char *cgit_query_sha2 = NULL;
41int cgit_query_ofs = 0; 42int cgit_query_ofs = 0;
42 43
43int htmlfd = 0; 44int htmlfd = 0;
44 45
45void cgit_global_config_cb(const char *name, const char *value) 46void cgit_global_config_cb(const char *name, const char *value)
46{ 47{
47 if (!strcmp(name, "root")) 48 if (!strcmp(name, "root"))
48 cgit_root = xstrdup(value); 49 cgit_root = xstrdup(value);
49 else if (!strcmp(name, "root-title")) 50 else if (!strcmp(name, "root-title"))
50 cgit_root_title = xstrdup(value); 51 cgit_root_title = xstrdup(value);
51 else if (!strcmp(name, "css")) 52 else if (!strcmp(name, "css"))
52 cgit_css = xstrdup(value); 53 cgit_css = xstrdup(value);
53 else if (!strcmp(name, "logo")) 54 else if (!strcmp(name, "logo"))
54 cgit_logo = xstrdup(value); 55 cgit_logo = xstrdup(value);
55 else if (!strcmp(name, "logo-link")) 56 else if (!strcmp(name, "logo-link"))
56 cgit_logo_link = xstrdup(value); 57 cgit_logo_link = xstrdup(value);
57 else if (!strcmp(name, "virtual-root")) 58 else if (!strcmp(name, "virtual-root"))
58 cgit_virtual_root = xstrdup(value); 59 cgit_virtual_root = xstrdup(value);
59 else if (!strcmp(name, "nocache")) 60 else if (!strcmp(name, "nocache"))
60 cgit_nocache = atoi(value); 61 cgit_nocache = atoi(value);
61 else if (!strcmp(name, "cache-root")) 62 else if (!strcmp(name, "cache-root"))
62 cgit_cache_root = xstrdup(value); 63 cgit_cache_root = xstrdup(value);
63 else if (!strcmp(name, "cache-root-ttl")) 64 else if (!strcmp(name, "cache-root-ttl"))
64 cgit_cache_root_ttl = atoi(value); 65 cgit_cache_root_ttl = atoi(value);
65 else if (!strcmp(name, "cache-repo-ttl")) 66 else if (!strcmp(name, "cache-repo-ttl"))
66 cgit_cache_repo_ttl = atoi(value); 67 cgit_cache_repo_ttl = atoi(value);
67 else if (!strcmp(name, "cache-static-ttl")) 68 else if (!strcmp(name, "cache-static-ttl"))
68 cgit_cache_static_ttl = atoi(value); 69 cgit_cache_static_ttl = atoi(value);
69 else if (!strcmp(name, "cache-dynamic-ttl")) 70 else if (!strcmp(name, "cache-dynamic-ttl"))
70 cgit_cache_dynamic_ttl = atoi(value); 71 cgit_cache_dynamic_ttl = atoi(value);
71} 72}
72 73
73void cgit_repo_config_cb(const char *name, const char *value) 74void cgit_repo_config_cb(const char *name, const char *value)
74{ 75{
75 if (!strcmp(name, "name")) 76 if (!strcmp(name, "name"))
76 cgit_repo_name = xstrdup(value); 77 cgit_repo_name = xstrdup(value);
77 else if (!strcmp(name, "desc")) 78 else if (!strcmp(name, "desc"))
78 cgit_repo_desc = xstrdup(value); 79 cgit_repo_desc = xstrdup(value);
79 else if (!strcmp(name, "owner")) 80 else if (!strcmp(name, "owner"))
80 cgit_repo_owner = xstrdup(value); 81 cgit_repo_owner = xstrdup(value);
81} 82}
82 83
83void cgit_querystring_cb(const char *name, const char *value) 84void cgit_querystring_cb(const char *name, const char *value)
84{ 85{
85 if (!strcmp(name,"r")) { 86 if (!strcmp(name,"r")) {
86 cgit_query_repo = xstrdup(value); 87 cgit_query_repo = xstrdup(value);
87 } else if (!strcmp(name, "p")) { 88 } else if (!strcmp(name, "p")) {
88 cgit_query_page = xstrdup(value); 89 cgit_query_page = xstrdup(value);
90 } else if (!strcmp(name, "q")) {
91 cgit_query_search = xstrdup(value);
89 } else if (!strcmp(name, "h")) { 92 } else if (!strcmp(name, "h")) {
90 cgit_query_head = xstrdup(value); 93 cgit_query_head = xstrdup(value);
91 cgit_query_has_symref = 1; 94 cgit_query_has_symref = 1;
92 } else if (!strcmp(name, "id")) { 95 } else if (!strcmp(name, "id")) {
93 cgit_query_sha1 = xstrdup(value); 96 cgit_query_sha1 = xstrdup(value);
94 cgit_query_has_sha1 = 1; 97 cgit_query_has_sha1 = 1;
95 } else if (!strcmp(name, "id2")) { 98 } else if (!strcmp(name, "id2")) {
96 cgit_query_sha2 = xstrdup(value); 99 cgit_query_sha2 = xstrdup(value);
97 cgit_query_has_sha1 = 1; 100 cgit_query_has_sha1 = 1;
98 } else if (!strcmp(name, "ofs")) { 101 } else if (!strcmp(name, "ofs")) {
99 cgit_query_ofs = atoi(value); 102 cgit_query_ofs = atoi(value);
100 } 103 }
101} 104}
102 105
103void *cgit_free_commitinfo(struct commitinfo *info) 106void *cgit_free_commitinfo(struct commitinfo *info)
104{ 107{
105 free(info->author); 108 free(info->author);
106 free(info->author_email); 109 free(info->author_email);
107 free(info->committer); 110 free(info->committer);
108 free(info->committer_email); 111 free(info->committer_email);
109 free(info->subject); 112 free(info->subject);
110 free(info); 113 free(info);
111 return NULL; 114 return NULL;
112} 115}
diff --git a/ui-repolist.c b/ui-repolist.c
index 7090c12..9f12b18 100644
--- a/ui-repolist.c
+++ b/ui-repolist.c
@@ -1,63 +1,63 @@
1/* ui-repolist.c: functions for generating the repolist page 1/* ui-repolist.c: functions for generating the repolist 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
11void cgit_print_repolist(struct cacheitem *item) 11void cgit_print_repolist(struct cacheitem *item)
12{ 12{
13 DIR *d; 13 DIR *d;
14 struct dirent *de; 14 struct dirent *de;
15 struct stat st; 15 struct stat st;
16 char *name; 16 char *name;
17 17
18 chdir(cgit_root); 18 chdir(cgit_root);
19 cgit_print_docstart(cgit_root_title, item); 19 cgit_print_docstart(cgit_root_title, item);
20 cgit_print_pageheader(cgit_root_title); 20 cgit_print_pageheader(cgit_root_title, 0);
21 21
22 if (!(d = opendir("."))) { 22 if (!(d = opendir("."))) {
23 cgit_print_error(fmt("Unable to scan repository directory: %s", 23 cgit_print_error(fmt("Unable to scan repository directory: %s",
24 strerror(errno))); 24 strerror(errno)));
25 cgit_print_docend(); 25 cgit_print_docend();
26 return; 26 return;
27 } 27 }
28 28
29 html("<h2>Repositories</h2>\n"); 29 html("<h2>Repositories</h2>\n");
30 html("<table class='list nowrap'>"); 30 html("<table class='list nowrap'>");
31 html("<tr>" 31 html("<tr>"
32 "<th class='left'>Name</th>" 32 "<th class='left'>Name</th>"
33 "<th class='left'>Description</th>" 33 "<th class='left'>Description</th>"
34 "<th class='left'>Owner</th></tr>\n"); 34 "<th class='left'>Owner</th></tr>\n");
35 while ((de = readdir(d)) != NULL) { 35 while ((de = readdir(d)) != NULL) {
36 if (de->d_name[0] == '.') 36 if (de->d_name[0] == '.')
37 continue; 37 continue;
38 if (stat(de->d_name, &st) < 0) 38 if (stat(de->d_name, &st) < 0)
39 continue; 39 continue;
40 if (!S_ISDIR(st.st_mode)) 40 if (!S_ISDIR(st.st_mode))
41 continue; 41 continue;
42 42
43 cgit_repo_name = cgit_repo_desc = cgit_repo_owner = NULL; 43 cgit_repo_name = cgit_repo_desc = cgit_repo_owner = NULL;
44 name = fmt("%s/info/cgit", de->d_name); 44 name = fmt("%s/info/cgit", de->d_name);
45 if (cgit_read_config(name, cgit_repo_config_cb)) 45 if (cgit_read_config(name, cgit_repo_config_cb))
46 continue; 46 continue;
47 47
48 html("<tr><td>"); 48 html("<tr><td>");
49 html_link_open(cgit_repourl(de->d_name), NULL, NULL); 49 html_link_open(cgit_repourl(de->d_name), NULL, NULL);
50 html_txt(cgit_repo_name); 50 html_txt(cgit_repo_name);
51 html_link_close(); 51 html_link_close();
52 html("</td><td>"); 52 html("</td><td>");
53 html_txt(cgit_repo_desc); 53 html_txt(cgit_repo_desc);
54 html("</td><td>"); 54 html("</td><td>");
55 html_txt(cgit_repo_owner); 55 html_txt(cgit_repo_owner);
56 html("</td></tr>\n"); 56 html("</td></tr>\n");
57 } 57 }
58 closedir(d); 58 closedir(d);
59 html("</table>"); 59 html("</table>");
60 cgit_print_docend(); 60 cgit_print_docend();
61} 61}
62 62
63 63
diff --git a/ui-shared.c b/ui-shared.c
index 9ec4be8..b9c1243 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -1,113 +1,139 @@
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 10
11const char cgit_doctype[] = 11const char cgit_doctype[] =
12"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" 12"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
13" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"; 13" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
14 14
15static char *http_date(time_t t) 15static char *http_date(time_t t)
16{ 16{
17 static char day[][4] = 17 static char day[][4] =
18 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 18 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
19 static char month[][4] = 19 static char month[][4] =
20 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 20 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
21 "Jul", "Aug", "Sep", "Oct", "Now", "Dec"}; 21 "Jul", "Aug", "Sep", "Oct", "Now", "Dec"};
22 struct tm *tm = gmtime(&t); 22 struct tm *tm = gmtime(&t);
23 return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday], 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, 24 tm->tm_mday, month[tm->tm_mon], 1900+tm->tm_year,
25 tm->tm_hour, tm->tm_min, tm->tm_sec); 25 tm->tm_hour, tm->tm_min, tm->tm_sec);
26} 26}
27 27
28static int ttl_seconds(int ttl) 28static int ttl_seconds(int ttl)
29{ 29{
30 if (ttl<0) 30 if (ttl<0)
31 return 60 * 60 * 24 * 365; 31 return 60 * 60 * 24 * 365;
32 else 32 else
33 return ttl * 60; 33 return ttl * 60;
34} 34}
35 35
36void cgit_print_error(char *msg) 36void cgit_print_error(char *msg)
37{ 37{
38 html("<div class='error'>"); 38 html("<div class='error'>");
39 html_txt(msg); 39 html_txt(msg);
40 html("</div>\n"); 40 html("</div>\n");
41} 41}
42 42
43char *cgit_repourl(const char *reponame) 43char *cgit_repourl(const char *reponame)
44{ 44{
45 if (cgit_virtual_root) { 45 if (cgit_virtual_root) {
46 return fmt("%s/%s/", cgit_virtual_root, reponame); 46 return fmt("%s/%s/", cgit_virtual_root, reponame);
47 } else { 47 } else {
48 return fmt("?r=%s", reponame); 48 return fmt("?r=%s", reponame);
49 } 49 }
50} 50}
51 51
52char *cgit_pageurl(const char *reponame, const char *pagename, 52char *cgit_pageurl(const char *reponame, const char *pagename,
53 const char *query) 53 const char *query)
54{ 54{
55 if (cgit_virtual_root) { 55 if (cgit_virtual_root) {
56 return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame, 56 return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame,
57 pagename, query); 57 pagename, query);
58 } else { 58 } else {
59 return fmt("?r=%s&p=%s&%s", reponame, pagename, query); 59 return fmt("?r=%s&p=%s&%s", reponame, pagename, query);
60 } 60 }
61} 61}
62 62
63char *cgit_currurl()
64{
65 if (!cgit_virtual_root)
66 return "./cgit.cgi";
67 else if (cgit_query_page)
68 return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page);
69 else if (cgit_query_repo)
70 return fmt("%s/%s/", cgit_virtual_root, cgit_query_repo);
71 else
72 return fmt("%s/", cgit_virtual_root);
73}
74
63 75
64void cgit_print_date(unsigned long secs) 76void cgit_print_date(unsigned long secs)
65{ 77{
66 char buf[32]; 78 char buf[32];
67 struct tm *time; 79 struct tm *time;
68 80
69 time = gmtime(&secs); 81 time = gmtime(&secs);
70 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", time); 82 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", time);
71 html_txt(buf); 83 html_txt(buf);
72 84
73} 85}
74 86
75void cgit_print_docstart(char *title, struct cacheitem *item) 87void cgit_print_docstart(char *title, struct cacheitem *item)
76{ 88{
77 html("Content-Type: text/html; charset=utf-8\n"); 89 html("Content-Type: text/html; charset=utf-8\n");
78 htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); 90 htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime));
79 htmlf("Expires: %s\n", http_date(item->st.st_mtime + 91 htmlf("Expires: %s\n", http_date(item->st.st_mtime +
80 ttl_seconds(item->ttl))); 92 ttl_seconds(item->ttl)));
81 html("\n"); 93 html("\n");
82 html(cgit_doctype); 94 html(cgit_doctype);
83 html("<html>\n"); 95 html("<html>\n");
84 html("<head>\n"); 96 html("<head>\n");
85 html("<title>"); 97 html("<title>");
86 html_txt(title); 98 html_txt(title);
87 html("</title>\n"); 99 html("</title>\n");
88 htmlf("<meta name='generator' content='cgit v%s'/>\n", cgit_version); 100 htmlf("<meta name='generator' content='cgit v%s'/>\n", cgit_version);
89 html("<link rel='stylesheet' type='text/css' href='"); 101 html("<link rel='stylesheet' type='text/css' href='");
90 html_attr(cgit_css); 102 html_attr(cgit_css);
91 html("'/>\n"); 103 html("'/>\n");
92 html("</head>\n"); 104 html("</head>\n");
93 html("<body>\n"); 105 html("<body>\n");
94} 106}
95 107
96void cgit_print_docend() 108void cgit_print_docend()
97{ 109{
98 html("</body>\n</html>\n"); 110 html("</body>\n</html>\n");
99} 111}
100 112
101void cgit_print_pageheader(char *title) 113void cgit_print_pageheader(char *title, int show_search)
102{ 114{
103 html("<div id='header'>"); 115 html("<div id='header'>");
104 htmlf("<a href='%s'>", cgit_logo_link); 116 htmlf("<a href='%s'>", cgit_logo_link);
105 htmlf("<img id='logo' src='%s'/>\n", cgit_logo); 117 htmlf("<img id='logo' src='%s'/>\n", cgit_logo);
106 htmlf("</a>"); 118 htmlf("</a>");
119 if (show_search) {
120 html("<form method='get' href='");
121 html_attr(cgit_currurl());
122 html("'>");
123 if (cgit_query_head)
124 html_hidden("h", cgit_query_head);
125 if (cgit_query_sha1)
126 html_hidden("id", cgit_query_sha1);
127 if (cgit_query_sha2)
128 html_hidden("id2", cgit_query_sha2);
129 html("<input type='text' name='q' value='");
130 html_attr(cgit_query_search);
131 html("'/></form>");
132 }
107 if (cgit_query_repo) 133 if (cgit_query_repo)
108 htmlf("<a href='%s'>", cgit_repourl(cgit_query_repo)); 134 htmlf("<a href='%s'>", cgit_repourl(cgit_query_repo));
109 html_txt(title); 135 html_txt(title);
110 if (cgit_query_repo) 136 if (cgit_query_repo)
111 html("</a>"); 137 html("</a>");
112 html("</div>"); 138 html("</div>");
113} 139}