summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c2
-rw-r--r--cgit.css15
-rw-r--r--cgit.h1
-rw-r--r--ui-log.c35
-rw-r--r--ui-refs.c3
-rw-r--r--ui-repolist.c2
-rw-r--r--ui-shared.c12
-rw-r--r--ui-shared.h2
-rw-r--r--ui-tree.c2
9 files changed, 61 insertions, 13 deletions
diff --git a/cgit.c b/cgit.c
index e09c86e..166fbc6 100644
--- a/cgit.c
+++ b/cgit.c
@@ -95,128 +95,130 @@ void config_cb(const char *name, const char *value)
95 else if (!strcmp(name, "repo.url")) 95 else if (!strcmp(name, "repo.url"))
96 ctx.repo = cgit_add_repo(value); 96 ctx.repo = cgit_add_repo(value);
97 else if (!strcmp(name, "repo.name")) 97 else if (!strcmp(name, "repo.name"))
98 ctx.repo->name = xstrdup(value); 98 ctx.repo->name = xstrdup(value);
99 else if (ctx.repo && !strcmp(name, "repo.path")) 99 else if (ctx.repo && !strcmp(name, "repo.path"))
100 ctx.repo->path = trim_end(value, '/'); 100 ctx.repo->path = trim_end(value, '/');
101 else if (ctx.repo && !strcmp(name, "repo.clone-url")) 101 else if (ctx.repo && !strcmp(name, "repo.clone-url"))
102 ctx.repo->clone_url = xstrdup(value); 102 ctx.repo->clone_url = xstrdup(value);
103 else if (ctx.repo && !strcmp(name, "repo.desc")) 103 else if (ctx.repo && !strcmp(name, "repo.desc"))
104 ctx.repo->desc = xstrdup(value); 104 ctx.repo->desc = xstrdup(value);
105 else if (ctx.repo && !strcmp(name, "repo.owner")) 105 else if (ctx.repo && !strcmp(name, "repo.owner"))
106 ctx.repo->owner = xstrdup(value); 106 ctx.repo->owner = xstrdup(value);
107 else if (ctx.repo && !strcmp(name, "repo.defbranch")) 107 else if (ctx.repo && !strcmp(name, "repo.defbranch"))
108 ctx.repo->defbranch = xstrdup(value); 108 ctx.repo->defbranch = xstrdup(value);
109 else if (ctx.repo && !strcmp(name, "repo.snapshots")) 109 else if (ctx.repo && !strcmp(name, "repo.snapshots"))
110 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ 110 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
111 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) 111 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount"))
112 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 112 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
113 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) 113 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount"))
114 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 114 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
115 else if (ctx.repo && !strcmp(name, "repo.module-link")) 115 else if (ctx.repo && !strcmp(name, "repo.module-link"))
116 ctx.repo->module_link= xstrdup(value); 116 ctx.repo->module_link= xstrdup(value);
117 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { 117 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
118 if (*value == '/') 118 if (*value == '/')
119 ctx.repo->readme = xstrdup(value); 119 ctx.repo->readme = xstrdup(value);
120 else 120 else
121 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); 121 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value));
122 } else if (!strcmp(name, "include")) 122 } else if (!strcmp(name, "include"))
123 parse_configfile(value, config_cb); 123 parse_configfile(value, config_cb);
124} 124}
125 125
126static void querystring_cb(const char *name, const char *value) 126static void querystring_cb(const char *name, const char *value)
127{ 127{
128 if (!strcmp(name,"r")) { 128 if (!strcmp(name,"r")) {
129 ctx.qry.repo = xstrdup(value); 129 ctx.qry.repo = xstrdup(value);
130 ctx.repo = cgit_get_repoinfo(value); 130 ctx.repo = cgit_get_repoinfo(value);
131 } else if (!strcmp(name, "p")) { 131 } else if (!strcmp(name, "p")) {
132 ctx.qry.page = xstrdup(value); 132 ctx.qry.page = xstrdup(value);
133 } else if (!strcmp(name, "url")) { 133 } else if (!strcmp(name, "url")) {
134 ctx.qry.url = xstrdup(value); 134 ctx.qry.url = xstrdup(value);
135 cgit_parse_url(value); 135 cgit_parse_url(value);
136 } else if (!strcmp(name, "qt")) { 136 } else if (!strcmp(name, "qt")) {
137 ctx.qry.grep = xstrdup(value); 137 ctx.qry.grep = xstrdup(value);
138 } else if (!strcmp(name, "q")) { 138 } else if (!strcmp(name, "q")) {
139 ctx.qry.search = xstrdup(value); 139 ctx.qry.search = xstrdup(value);
140 } else if (!strcmp(name, "h")) { 140 } else if (!strcmp(name, "h")) {
141 ctx.qry.head = xstrdup(value); 141 ctx.qry.head = xstrdup(value);
142 ctx.qry.has_symref = 1; 142 ctx.qry.has_symref = 1;
143 } else if (!strcmp(name, "id")) { 143 } else if (!strcmp(name, "id")) {
144 ctx.qry.sha1 = xstrdup(value); 144 ctx.qry.sha1 = xstrdup(value);
145 ctx.qry.has_sha1 = 1; 145 ctx.qry.has_sha1 = 1;
146 } else if (!strcmp(name, "id2")) { 146 } else if (!strcmp(name, "id2")) {
147 ctx.qry.sha2 = xstrdup(value); 147 ctx.qry.sha2 = xstrdup(value);
148 ctx.qry.has_sha1 = 1; 148 ctx.qry.has_sha1 = 1;
149 } else if (!strcmp(name, "ofs")) { 149 } else if (!strcmp(name, "ofs")) {
150 ctx.qry.ofs = atoi(value); 150 ctx.qry.ofs = atoi(value);
151 } else if (!strcmp(name, "path")) { 151 } else if (!strcmp(name, "path")) {
152 ctx.qry.path = trim_end(value, '/'); 152 ctx.qry.path = trim_end(value, '/');
153 } else if (!strcmp(name, "name")) { 153 } else if (!strcmp(name, "name")) {
154 ctx.qry.name = xstrdup(value); 154 ctx.qry.name = xstrdup(value);
155 } else if (!strcmp(name, "mimetype")) { 155 } else if (!strcmp(name, "mimetype")) {
156 ctx.qry.mimetype = xstrdup(value); 156 ctx.qry.mimetype = xstrdup(value);
157 } else if (!strcmp(name, "s")){ 157 } else if (!strcmp(name, "s")){
158 ctx.qry.sort = xstrdup(value); 158 ctx.qry.sort = xstrdup(value);
159 } else if (!strcmp(name, "showmsg")) {
160 ctx.qry.showmsg = atoi(value);
159 } 161 }
160} 162}
161 163
162static void prepare_context(struct cgit_context *ctx) 164static void prepare_context(struct cgit_context *ctx)
163{ 165{
164 memset(ctx, 0, sizeof(ctx)); 166 memset(ctx, 0, sizeof(ctx));
165 ctx->cfg.agefile = "info/web/last-modified"; 167 ctx->cfg.agefile = "info/web/last-modified";
166 ctx->cfg.nocache = 0; 168 ctx->cfg.nocache = 0;
167 ctx->cfg.cache_size = 0; 169 ctx->cfg.cache_size = 0;
168 ctx->cfg.cache_dynamic_ttl = 5; 170 ctx->cfg.cache_dynamic_ttl = 5;
169 ctx->cfg.cache_max_create_time = 5; 171 ctx->cfg.cache_max_create_time = 5;
170 ctx->cfg.cache_repo_ttl = 5; 172 ctx->cfg.cache_repo_ttl = 5;
171 ctx->cfg.cache_root = CGIT_CACHE_ROOT; 173 ctx->cfg.cache_root = CGIT_CACHE_ROOT;
172 ctx->cfg.cache_root_ttl = 5; 174 ctx->cfg.cache_root_ttl = 5;
173 ctx->cfg.cache_static_ttl = -1; 175 ctx->cfg.cache_static_ttl = -1;
174 ctx->cfg.css = "/cgit.css"; 176 ctx->cfg.css = "/cgit.css";
175 ctx->cfg.logo = "/git-logo.png"; 177 ctx->cfg.logo = "/git-logo.png";
176 ctx->cfg.local_time = 0; 178 ctx->cfg.local_time = 0;
177 ctx->cfg.max_repo_count = 50; 179 ctx->cfg.max_repo_count = 50;
178 ctx->cfg.max_commit_count = 50; 180 ctx->cfg.max_commit_count = 50;
179 ctx->cfg.max_lock_attempts = 5; 181 ctx->cfg.max_lock_attempts = 5;
180 ctx->cfg.max_msg_len = 80; 182 ctx->cfg.max_msg_len = 80;
181 ctx->cfg.max_repodesc_len = 80; 183 ctx->cfg.max_repodesc_len = 80;
182 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 184 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
183 ctx->cfg.renamelimit = -1; 185 ctx->cfg.renamelimit = -1;
184 ctx->cfg.robots = "index, nofollow"; 186 ctx->cfg.robots = "index, nofollow";
185 ctx->cfg.root_title = "Git repository browser"; 187 ctx->cfg.root_title = "Git repository browser";
186 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 188 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
187 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 189 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
188 ctx->cfg.summary_branches = 10; 190 ctx->cfg.summary_branches = 10;
189 ctx->cfg.summary_log = 10; 191 ctx->cfg.summary_log = 10;
190 ctx->cfg.summary_tags = 10; 192 ctx->cfg.summary_tags = 10;
191 ctx->page.mimetype = "text/html"; 193 ctx->page.mimetype = "text/html";
192 ctx->page.charset = PAGE_ENCODING; 194 ctx->page.charset = PAGE_ENCODING;
193 ctx->page.filename = NULL; 195 ctx->page.filename = NULL;
194 ctx->page.size = 0; 196 ctx->page.size = 0;
195 ctx->page.modified = time(NULL); 197 ctx->page.modified = time(NULL);
196 ctx->page.expires = ctx->page.modified; 198 ctx->page.expires = ctx->page.modified;
197} 199}
198 200
199struct refmatch { 201struct refmatch {
200 char *req_ref; 202 char *req_ref;
201 char *first_ref; 203 char *first_ref;
202 int match; 204 int match;
203}; 205};
204 206
205int find_current_ref(const char *refname, const unsigned char *sha1, 207int find_current_ref(const char *refname, const unsigned char *sha1,
206 int flags, void *cb_data) 208 int flags, void *cb_data)
207{ 209{
208 struct refmatch *info; 210 struct refmatch *info;
209 211
210 info = (struct refmatch *)cb_data; 212 info = (struct refmatch *)cb_data;
211 if (!strcmp(refname, info->req_ref)) 213 if (!strcmp(refname, info->req_ref))
212 info->match = 1; 214 info->match = 1;
213 if (!info->first_ref) 215 if (!info->first_ref)
214 info->first_ref = xstrdup(refname); 216 info->first_ref = xstrdup(refname);
215 return info->match; 217 return info->match;
216} 218}
217 219
218char *find_default_branch(struct cgit_repo *repo) 220char *find_default_branch(struct cgit_repo *repo)
219{ 221{
220 struct refmatch info; 222 struct refmatch info;
221 char *ref; 223 char *ref;
222 224
diff --git a/cgit.css b/cgit.css
index a37d218..7928c2f 100644
--- a/cgit.css
+++ b/cgit.css
@@ -59,151 +59,166 @@ table#header td.form select {
59 59
60table#header td.sub { 60table#header td.sub {
61 color: #777; 61 color: #777;
62 border-top: solid 1px #ccc; 62 border-top: solid 1px #ccc;
63 padding-left: 10px; 63 padding-left: 10px;
64} 64}
65 65
66table.tabs { 66table.tabs {
67 /* border-bottom: solid 2px #ccc; */ 67 /* border-bottom: solid 2px #ccc; */
68 border-collapse: collapse; 68 border-collapse: collapse;
69 margin-top: 2em; 69 margin-top: 2em;
70 margin-bottom: 0px; 70 margin-bottom: 0px;
71 width: 100%; 71 width: 100%;
72} 72}
73 73
74table.tabs td { 74table.tabs td {
75 padding: 0px 1em; 75 padding: 0px 1em;
76 vertical-align: bottom; 76 vertical-align: bottom;
77} 77}
78 78
79table.tabs td a { 79table.tabs td a {
80 padding: 2px 0.75em; 80 padding: 2px 0.75em;
81 color: #777; 81 color: #777;
82 font-size: 110%; 82 font-size: 110%;
83} 83}
84 84
85table.tabs td a.active { 85table.tabs td a.active {
86 color: #000; 86 color: #000;
87 background-color: #ccc; 87 background-color: #ccc;
88} 88}
89 89
90table.tabs td.form { 90table.tabs td.form {
91 text-align: right; 91 text-align: right;
92} 92}
93 93
94table.tabs td.form form { 94table.tabs td.form form {
95 padding-bottom: 2px; 95 padding-bottom: 2px;
96 font-size: 90%; 96 font-size: 90%;
97 white-space: nowrap; 97 white-space: nowrap;
98} 98}
99 99
100table.tabs td.form input, 100table.tabs td.form input,
101table.tabs td.form select { 101table.tabs td.form select {
102 font-size: 90%; 102 font-size: 90%;
103} 103}
104 104
105div.content { 105div.content {
106 margin: 0px; 106 margin: 0px;
107 padding: 2em; 107 padding: 2em;
108 border-top: solid 3px #ccc; 108 border-top: solid 3px #ccc;
109 border-bottom: solid 3px #ccc; 109 border-bottom: solid 3px #ccc;
110} 110}
111 111
112 112
113table.list { 113table.list {
114 width: 100%; 114 width: 100%;
115 border: none; 115 border: none;
116 border-collapse: collapse; 116 border-collapse: collapse;
117} 117}
118 118
119table.list tr { 119table.list tr {
120 background: white; 120 background: white;
121} 121}
122 122
123table.list tr.logheader {
124 background: #eee;
125}
126
123table.list tr:hover { 127table.list tr:hover {
124 background: #eee; 128 background: #eee;
125} 129}
126 130
127table.list tr.nohover:hover { 131table.list tr.nohover:hover {
128 background: white; 132 background: white;
129} 133}
130 134
131table.list th { 135table.list th {
132 font-weight: bold; 136 font-weight: bold;
133 /* color: #888; 137 /* color: #888;
134 border-top: dashed 1px #888; 138 border-top: dashed 1px #888;
135 border-bottom: dashed 1px #888; 139 border-bottom: dashed 1px #888;
136 */ 140 */
137 padding: 0.1em 0.5em 0.05em 0.5em; 141 padding: 0.1em 0.5em 0.05em 0.5em;
138 vertical-align: baseline; 142 vertical-align: baseline;
139} 143}
140 144
141table.list td { 145table.list td {
142 border: none; 146 border: none;
143 padding: 0.1em 0.5em 0.1em 0.5em; 147 padding: 0.1em 0.5em 0.1em 0.5em;
144} 148}
145 149
150table.list td.logsubject {
151 font-family: monospace;
152 font-weight: bold;
153}
154
155table.list td.logmsg {
156 font-family: monospace;
157 white-space: pre;
158 padding: 1em 0em 2em 0em;
159}
160
146table.list td a { 161table.list td a {
147 color: black; 162 color: black;
148} 163}
149 164
150table.list td a:hover { 165table.list td a:hover {
151 color: #00f; 166 color: #00f;
152} 167}
153 168
154img { 169img {
155 border: none; 170 border: none;
156} 171}
157 172
158input#switch-btn { 173input#switch-btn {
159 margin: 2px 0px 0px 0px; 174 margin: 2px 0px 0px 0px;
160} 175}
161 176
162td#sidebar input.txt { 177td#sidebar input.txt {
163 width: 100%; 178 width: 100%;
164 margin: 2px 0px 0px 0px; 179 margin: 2px 0px 0px 0px;
165} 180}
166 181
167table#grid { 182table#grid {
168 margin: 0px; 183 margin: 0px;
169} 184}
170 185
171td#content { 186td#content {
172 vertical-align: top; 187 vertical-align: top;
173 padding: 1em 2em 1em 1em; 188 padding: 1em 2em 1em 1em;
174 border: none; 189 border: none;
175} 190}
176 191
177div#summary { 192div#summary {
178 vertical-align: top; 193 vertical-align: top;
179 margin-bottom: 1em; 194 margin-bottom: 1em;
180} 195}
181 196
182table#downloads { 197table#downloads {
183 float: right; 198 float: right;
184 border-collapse: collapse; 199 border-collapse: collapse;
185 border: solid 1px #777; 200 border: solid 1px #777;
186 margin-left: 0.5em; 201 margin-left: 0.5em;
187 margin-bottom: 0.5em; 202 margin-bottom: 0.5em;
188} 203}
189 204
190table#downloads th { 205table#downloads th {
191 background-color: #ccc; 206 background-color: #ccc;
192} 207}
193 208
194div#blob { 209div#blob {
195 border: solid 1px black; 210 border: solid 1px black;
196} 211}
197 212
198div.error { 213div.error {
199 color: red; 214 color: red;
200 font-weight: bold; 215 font-weight: bold;
201 margin: 1em 2em; 216 margin: 1em 2em;
202} 217}
203 218
204a.ls-blob, a.ls-dir, a.ls-mod { 219a.ls-blob, a.ls-dir, a.ls-mod {
205 font-family: monospace; 220 font-family: monospace;
206} 221}
207 222
208td.ls-size { 223td.ls-size {
209 text-align: right; 224 text-align: right;
diff --git a/cgit.h b/cgit.h
index f1fbeca..cb2f176 100644
--- a/cgit.h
+++ b/cgit.h
@@ -62,128 +62,129 @@ struct cgit_repo {
62 int enable_log_filecount; 62 int enable_log_filecount;
63 int enable_log_linecount; 63 int enable_log_linecount;
64 time_t mtime; 64 time_t mtime;
65}; 65};
66 66
67struct cgit_repolist { 67struct cgit_repolist {
68 int length; 68 int length;
69 int count; 69 int count;
70 struct cgit_repo *repos; 70 struct cgit_repo *repos;
71}; 71};
72 72
73struct commitinfo { 73struct commitinfo {
74 struct commit *commit; 74 struct commit *commit;
75 char *author; 75 char *author;
76 char *author_email; 76 char *author_email;
77 unsigned long author_date; 77 unsigned long author_date;
78 char *committer; 78 char *committer;
79 char *committer_email; 79 char *committer_email;
80 unsigned long committer_date; 80 unsigned long committer_date;
81 char *subject; 81 char *subject;
82 char *msg; 82 char *msg;
83 char *msg_encoding; 83 char *msg_encoding;
84}; 84};
85 85
86struct taginfo { 86struct taginfo {
87 char *tagger; 87 char *tagger;
88 char *tagger_email; 88 char *tagger_email;
89 unsigned long tagger_date; 89 unsigned long tagger_date;
90 char *msg; 90 char *msg;
91}; 91};
92 92
93struct refinfo { 93struct refinfo {
94 const char *refname; 94 const char *refname;
95 struct object *object; 95 struct object *object;
96 union { 96 union {
97 struct taginfo *tag; 97 struct taginfo *tag;
98 struct commitinfo *commit; 98 struct commitinfo *commit;
99 }; 99 };
100}; 100};
101 101
102struct reflist { 102struct reflist {
103 struct refinfo **refs; 103 struct refinfo **refs;
104 int alloc; 104 int alloc;
105 int count; 105 int count;
106}; 106};
107 107
108struct cgit_query { 108struct cgit_query {
109 int has_symref; 109 int has_symref;
110 int has_sha1; 110 int has_sha1;
111 char *raw; 111 char *raw;
112 char *repo; 112 char *repo;
113 char *page; 113 char *page;
114 char *search; 114 char *search;
115 char *grep; 115 char *grep;
116 char *head; 116 char *head;
117 char *sha1; 117 char *sha1;
118 char *sha2; 118 char *sha2;
119 char *path; 119 char *path;
120 char *name; 120 char *name;
121 char *mimetype; 121 char *mimetype;
122 char *url; 122 char *url;
123 int ofs; 123 int ofs;
124 int nohead; 124 int nohead;
125 char *sort; 125 char *sort;
126 int showmsg;
126}; 127};
127 128
128struct cgit_config { 129struct cgit_config {
129 char *agefile; 130 char *agefile;
130 char *cache_root; 131 char *cache_root;
131 char *clone_prefix; 132 char *clone_prefix;
132 char *css; 133 char *css;
133 char *favicon; 134 char *favicon;
134 char *footer; 135 char *footer;
135 char *index_header; 136 char *index_header;
136 char *index_info; 137 char *index_info;
137 char *logo; 138 char *logo;
138 char *logo_link; 139 char *logo_link;
139 char *module_link; 140 char *module_link;
140 char *repo_group; 141 char *repo_group;
141 char *robots; 142 char *robots;
142 char *root_title; 143 char *root_title;
143 char *root_desc; 144 char *root_desc;
144 char *root_readme; 145 char *root_readme;
145 char *script_name; 146 char *script_name;
146 char *virtual_root; 147 char *virtual_root;
147 int cache_size; 148 int cache_size;
148 int cache_dynamic_ttl; 149 int cache_dynamic_ttl;
149 int cache_max_create_time; 150 int cache_max_create_time;
150 int cache_repo_ttl; 151 int cache_repo_ttl;
151 int cache_root_ttl; 152 int cache_root_ttl;
152 int cache_static_ttl; 153 int cache_static_ttl;
153 int enable_index_links; 154 int enable_index_links;
154 int enable_log_filecount; 155 int enable_log_filecount;
155 int enable_log_linecount; 156 int enable_log_linecount;
156 int local_time; 157 int local_time;
157 int max_repo_count; 158 int max_repo_count;
158 int max_commit_count; 159 int max_commit_count;
159 int max_lock_attempts; 160 int max_lock_attempts;
160 int max_msg_len; 161 int max_msg_len;
161 int max_repodesc_len; 162 int max_repodesc_len;
162 int nocache; 163 int nocache;
163 int renamelimit; 164 int renamelimit;
164 int snapshots; 165 int snapshots;
165 int summary_branches; 166 int summary_branches;
166 int summary_log; 167 int summary_log;
167 int summary_tags; 168 int summary_tags;
168}; 169};
169 170
170struct cgit_page { 171struct cgit_page {
171 time_t modified; 172 time_t modified;
172 time_t expires; 173 time_t expires;
173 size_t size; 174 size_t size;
174 char *mimetype; 175 char *mimetype;
175 char *charset; 176 char *charset;
176 char *filename; 177 char *filename;
177 char *title; 178 char *title;
178}; 179};
179 180
180struct cgit_context { 181struct cgit_context {
181 struct cgit_query qry; 182 struct cgit_query qry;
182 struct cgit_config cfg; 183 struct cgit_config cfg;
183 struct cgit_repo *repo; 184 struct cgit_repo *repo;
184 struct cgit_page page; 185 struct cgit_page page;
185}; 186};
186 187
187struct cgit_snapshot_format { 188struct cgit_snapshot_format {
188 const char *suffix; 189 const char *suffix;
189 const char *mimetype; 190 const char *mimetype;
diff --git a/ui-log.c b/ui-log.c
index d212984..2f90778 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -1,168 +1,189 @@
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#include "html.h" 10#include "html.h"
11#include "ui-shared.h" 11#include "ui-shared.h"
12 12
13int files, add_lines, rem_lines; 13int files, add_lines, rem_lines;
14 14
15void count_lines(char *line, int size) 15void count_lines(char *line, int size)
16{ 16{
17 if (size <= 0) 17 if (size <= 0)
18 return; 18 return;
19 19
20 if (line[0] == '+') 20 if (line[0] == '+')
21 add_lines++; 21 add_lines++;
22 22
23 else if (line[0] == '-') 23 else if (line[0] == '-')
24 rem_lines++; 24 rem_lines++;
25} 25}
26 26
27void inspect_files(struct diff_filepair *pair) 27void inspect_files(struct diff_filepair *pair)
28{ 28{
29 files++; 29 files++;
30 if (ctx.repo->enable_log_linecount) 30 if (ctx.repo->enable_log_linecount)
31 cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines); 31 cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines);
32} 32}
33 33
34void print_commit(struct commit *commit) 34void print_commit(struct commit *commit)
35{ 35{
36 struct commitinfo *info; 36 struct commitinfo *info;
37 char *tmp; 37 char *tmp;
38 int cols = 2;
38 39
39 info = cgit_parse_commit(commit); 40 info = cgit_parse_commit(commit);
40 html("<tr><td>"); 41 htmlf("<tr%s><td>",
42 ctx.qry.showmsg ? " class='logheader'" : "");
41 tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1)); 43 tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1));
42 tmp = cgit_pageurl(ctx.repo->url, "commit", tmp); 44 tmp = cgit_pageurl(ctx.repo->url, "commit", tmp);
43 html_link_open(tmp, NULL, NULL); 45 html_link_open(tmp, NULL, NULL);
44 cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); 46 cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
45 html_link_close(); 47 html_link_close();
46 html("</td><td>"); 48 htmlf("</td><td%s>",
49 ctx.qry.showmsg ? " class='logsubject'" : "");
47 cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, 50 cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,
48 sha1_to_hex(commit->object.sha1)); 51 sha1_to_hex(commit->object.sha1));
49 html("</td><td>"); 52 html("</td><td>");
50 html_txt(info->author); 53 html_txt(info->author);
51 if (ctx.repo->enable_log_filecount) { 54 if (ctx.repo->enable_log_filecount) {
52 files = 0; 55 files = 0;
53 add_lines = 0; 56 add_lines = 0;
54 rem_lines = 0; 57 rem_lines = 0;
55 cgit_diff_commit(commit, inspect_files); 58 cgit_diff_commit(commit, inspect_files);
56 html("</td><td>"); 59 html("</td><td>");
57 htmlf("%d", files); 60 htmlf("%d", files);
58 if (ctx.repo->enable_log_linecount) { 61 if (ctx.repo->enable_log_linecount) {
59 html("</td><td>"); 62 html("</td><td>");
60 htmlf("-%d/+%d", rem_lines, add_lines); 63 htmlf("-%d/+%d", rem_lines, add_lines);
61 } 64 }
62 } 65 }
63 html("</td></tr>\n"); 66 html("</td></tr>\n");
67 if (ctx.qry.showmsg) {
68 if (ctx.repo->enable_log_filecount) {
69 cols++;
70 if (ctx.repo->enable_log_linecount)
71 cols++;
72 }
73 htmlf("<tr class='nohover'><td/><td colspan='%d' class='logmsg'>",
74 cols);
75 html_txt(info->msg);
76 html("</td></tr>\n");
77 }
64 cgit_free_commitinfo(info); 78 cgit_free_commitinfo(info);
65} 79}
66 80
67static const char *disambiguate_ref(const char *ref) 81static const char *disambiguate_ref(const char *ref)
68{ 82{
69 unsigned char sha1[20]; 83 unsigned char sha1[20];
70 const char *longref; 84 const char *longref;
71 85
72 longref = fmt("refs/heads/%s", ref); 86 longref = fmt("refs/heads/%s", ref);
73 if (get_sha1(longref, sha1) == 0) 87 if (get_sha1(longref, sha1) == 0)
74 return longref; 88 return longref;
75 89
76 return ref; 90 return ref;
77} 91}
78 92
79void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern, 93void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern,
80 char *path, int pager) 94 char *path, int pager)
81{ 95{
82 struct rev_info rev; 96 struct rev_info rev;
83 struct commit *commit; 97 struct commit *commit;
84 const char *argv[] = {NULL, NULL, NULL, NULL, NULL}; 98 const char *argv[] = {NULL, NULL, NULL, NULL, NULL};
85 int argc = 2; 99 int argc = 2;
86 int i, columns = 3; 100 int i, columns = 3;
87 101
88 if (!tip) 102 if (!tip)
89 tip = ctx.qry.head; 103 tip = ctx.qry.head;
90 104
91 argv[1] = disambiguate_ref(tip); 105 argv[1] = disambiguate_ref(tip);
92 106
93 if (grep && pattern && (!strcmp(grep, "grep") || 107 if (grep && pattern && (!strcmp(grep, "grep") ||
94 !strcmp(grep, "author") || 108 !strcmp(grep, "author") ||
95 !strcmp(grep, "committer"))) 109 !strcmp(grep, "committer")))
96 argv[argc++] = fmt("--%s=%s", grep, pattern); 110 argv[argc++] = fmt("--%s=%s", grep, pattern);
97 111
98 if (path) { 112 if (path) {
99 argv[argc++] = "--"; 113 argv[argc++] = "--";
100 argv[argc++] = path; 114 argv[argc++] = path;
101 } 115 }
102 init_revisions(&rev, NULL); 116 init_revisions(&rev, NULL);
103 rev.abbrev = DEFAULT_ABBREV; 117 rev.abbrev = DEFAULT_ABBREV;
104 rev.commit_format = CMIT_FMT_DEFAULT; 118 rev.commit_format = CMIT_FMT_DEFAULT;
105 rev.verbose_header = 1; 119 rev.verbose_header = 1;
106 rev.show_root_diff = 0; 120 rev.show_root_diff = 0;
107 setup_revisions(argc, argv, &rev, NULL); 121 setup_revisions(argc, argv, &rev, NULL);
108 rev.grep_filter.regflags |= REG_ICASE; 122 rev.grep_filter.regflags |= REG_ICASE;
109 compile_grep_patterns(&rev.grep_filter); 123 compile_grep_patterns(&rev.grep_filter);
110 prepare_revision_walk(&rev); 124 prepare_revision_walk(&rev);
111 125
112 if (pager) 126 if (pager)
113 html("<table class='list nowrap'>"); 127 html("<table class='list nowrap'>");
114 128
115 html("<tr class='nohover'><th class='left'>Age</th>" 129 html("<tr class='nohover'><th class='left'>Age</th>"
116 "<th class='left'>Commit message</th>" 130 "<th class='left'>Commit message");
117 "<th class='left'>Author</th>"); 131 if (pager) {
132 html(" (");
133 cgit_log_link("toggle", NULL, NULL, ctx.qry.head, ctx.qry.sha1,
134 ctx.qry.path, ctx.qry.ofs, ctx.qry.grep,
135 ctx.qry.search, ctx.qry.showmsg ? 0 : 1);
136 html(")");
137 }
138 html("</th><th class='left'>Author</th>");
118 if (ctx.repo->enable_log_filecount) { 139 if (ctx.repo->enable_log_filecount) {
119 html("<th class='left'>Files</th>"); 140 html("<th class='left'>Files</th>");
120 columns++; 141 columns++;
121 if (ctx.repo->enable_log_linecount) { 142 if (ctx.repo->enable_log_linecount) {
122 html("<th class='left'>Lines</th>"); 143 html("<th class='left'>Lines</th>");
123 columns++; 144 columns++;
124 } 145 }
125 } 146 }
126 html("</tr>\n"); 147 html("</tr>\n");
127 148
128 if (ofs<0) 149 if (ofs<0)
129 ofs = 0; 150 ofs = 0;
130 151
131 for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) { 152 for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) {
132 free(commit->buffer); 153 free(commit->buffer);
133 commit->buffer = NULL; 154 commit->buffer = NULL;
134 free_commit_list(commit->parents); 155 free_commit_list(commit->parents);
135 commit->parents = NULL; 156 commit->parents = NULL;
136 } 157 }
137 158
138 for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) { 159 for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) {
139 print_commit(commit); 160 print_commit(commit);
140 free(commit->buffer); 161 free(commit->buffer);
141 commit->buffer = NULL; 162 commit->buffer = NULL;
142 free_commit_list(commit->parents); 163 free_commit_list(commit->parents);
143 commit->parents = NULL; 164 commit->parents = NULL;
144 } 165 }
145 if (pager) { 166 if (pager) {
146 htmlf("</table><div class='pager'>", 167 htmlf("</table><div class='pager'>",
147 columns); 168 columns);
148 if (ofs > 0) { 169 if (ofs > 0) {
149 cgit_log_link("[prev]", NULL, NULL, ctx.qry.head, 170 cgit_log_link("[prev]", NULL, NULL, ctx.qry.head,
150 ctx.qry.sha1, ctx.qry.path, 171 ctx.qry.sha1, ctx.qry.path,
151 ofs - cnt, ctx.qry.grep, 172 ofs - cnt, ctx.qry.grep,
152 ctx.qry.search); 173 ctx.qry.search, ctx.qry.showmsg);
153 html("&nbsp;"); 174 html("&nbsp;");
154 } 175 }
155 if ((commit = get_revision(&rev)) != NULL) { 176 if ((commit = get_revision(&rev)) != NULL) {
156 cgit_log_link("[next]", NULL, NULL, ctx.qry.head, 177 cgit_log_link("[next]", NULL, NULL, ctx.qry.head,
157 ctx.qry.sha1, ctx.qry.path, 178 ctx.qry.sha1, ctx.qry.path,
158 ofs + cnt, ctx.qry.grep, 179 ofs + cnt, ctx.qry.grep,
159 ctx.qry.search); 180 ctx.qry.search, ctx.qry.showmsg);
160 } 181 }
161 html("</div>"); 182 html("</div>");
162 } else if ((commit = get_revision(&rev)) != NULL) { 183 } else if ((commit = get_revision(&rev)) != NULL) {
163 html("<tr class='nohover'><td colspan='3'>"); 184 html("<tr class='nohover'><td colspan='3'>");
164 cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL, NULL, 0, 185 cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL, NULL, 0,
165 NULL, NULL); 186 NULL, NULL, ctx.qry.showmsg);
166 html("</td></tr>\n"); 187 html("</td></tr>\n");
167 } 188 }
168} 189}
diff --git a/ui-refs.c b/ui-refs.c
index 0805fc8..d61ee7c 100644
--- a/ui-refs.c
+++ b/ui-refs.c
@@ -1,125 +1,126 @@
1/* ui-refs.c: browse symbolic refs 1/* ui-refs.c: browse symbolic refs
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include "html.h" 10#include "html.h"
11#include "ui-shared.h" 11#include "ui-shared.h"
12 12
13static int header; 13static int header;
14 14
15static int cmp_age(int age1, int age2) 15static int cmp_age(int age1, int age2)
16{ 16{
17 if (age1 != 0 && age2 != 0) 17 if (age1 != 0 && age2 != 0)
18 return age2 - age1; 18 return age2 - age1;
19 19
20 if (age1 == 0 && age2 == 0) 20 if (age1 == 0 && age2 == 0)
21 return 0; 21 return 0;
22 22
23 if (age1 == 0) 23 if (age1 == 0)
24 return +1; 24 return +1;
25 25
26 return -1; 26 return -1;
27} 27}
28 28
29static int cmp_ref_name(const void *a, const void *b) 29static int cmp_ref_name(const void *a, const void *b)
30{ 30{
31 struct refinfo *r1 = *(struct refinfo **)a; 31 struct refinfo *r1 = *(struct refinfo **)a;
32 struct refinfo *r2 = *(struct refinfo **)b; 32 struct refinfo *r2 = *(struct refinfo **)b;
33 33
34 return strcmp(r1->refname, r2->refname); 34 return strcmp(r1->refname, r2->refname);
35} 35}
36 36
37static int cmp_branch_age(const void *a, const void *b) 37static int cmp_branch_age(const void *a, const void *b)
38{ 38{
39 struct refinfo *r1 = *(struct refinfo **)a; 39 struct refinfo *r1 = *(struct refinfo **)a;
40 struct refinfo *r2 = *(struct refinfo **)b; 40 struct refinfo *r2 = *(struct refinfo **)b;
41 41
42 return cmp_age(r1->commit->committer_date, r2->commit->committer_date); 42 return cmp_age(r1->commit->committer_date, r2->commit->committer_date);
43} 43}
44 44
45static int cmp_tag_age(const void *a, const void *b) 45static int cmp_tag_age(const void *a, const void *b)
46{ 46{
47 struct refinfo *r1 = *(struct refinfo **)a; 47 struct refinfo *r1 = *(struct refinfo **)a;
48 struct refinfo *r2 = *(struct refinfo **)b; 48 struct refinfo *r2 = *(struct refinfo **)b;
49 49
50 return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date); 50 return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date);
51} 51}
52 52
53static int print_branch(struct refinfo *ref) 53static int print_branch(struct refinfo *ref)
54{ 54{
55 struct commitinfo *info = ref->commit; 55 struct commitinfo *info = ref->commit;
56 char *name = (char *)ref->refname; 56 char *name = (char *)ref->refname;
57 57
58 if (!info) 58 if (!info)
59 return 1; 59 return 1;
60 html("<tr><td>"); 60 html("<tr><td>");
61 cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL); 61 cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL,
62 ctx.qry.showmsg);
62 html("</td><td>"); 63 html("</td><td>");
63 64
64 if (ref->object->type == OBJ_COMMIT) { 65 if (ref->object->type == OBJ_COMMIT) {
65 cgit_commit_link(info->subject, NULL, NULL, name, NULL); 66 cgit_commit_link(info->subject, NULL, NULL, name, NULL);
66 html("</td><td>"); 67 html("</td><td>");
67 html_txt(info->author); 68 html_txt(info->author);
68 html("</td><td colspan='2'>"); 69 html("</td><td colspan='2'>");
69 cgit_print_age(info->commit->date, -1, NULL); 70 cgit_print_age(info->commit->date, -1, NULL);
70 } else { 71 } else {
71 html("</td><td></td><td>"); 72 html("</td><td></td><td>");
72 cgit_object_link(ref->object); 73 cgit_object_link(ref->object);
73 } 74 }
74 html("</td></tr>\n"); 75 html("</td></tr>\n");
75 return 0; 76 return 0;
76} 77}
77 78
78static void print_tag_header() 79static void print_tag_header()
79{ 80{
80 html("<tr class='nohover'><th class='left'>Tag</th>" 81 html("<tr class='nohover'><th class='left'>Tag</th>"
81 "<th class='left'>Download</th>" 82 "<th class='left'>Download</th>"
82 "<th class='left'>Author</th>" 83 "<th class='left'>Author</th>"
83 "<th class='left' colspan='2'>Age</th></tr>\n"); 84 "<th class='left' colspan='2'>Age</th></tr>\n");
84 header = 1; 85 header = 1;
85} 86}
86 87
87static void print_tag_downloads(const struct cgit_repo *repo, const char *ref) 88static void print_tag_downloads(const struct cgit_repo *repo, const char *ref)
88{ 89{
89 const struct cgit_snapshot_format* f; 90 const struct cgit_snapshot_format* f;
90 char *filename; 91 char *filename;
91 const char *basename; 92 const char *basename;
92 93
93 if (!ref || strlen(ref) < 2) 94 if (!ref || strlen(ref) < 2)
94 return; 95 return;
95 96
96 basename = cgit_repobasename(repo->url); 97 basename = cgit_repobasename(repo->url);
97 if (prefixcmp(ref, basename) != 0) { 98 if (prefixcmp(ref, basename) != 0) {
98 if ((ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1])) 99 if ((ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1]))
99 ref++; 100 ref++;
100 if (isdigit(ref[0])) 101 if (isdigit(ref[0]))
101 ref = xstrdup(fmt("%s-%s", basename, ref)); 102 ref = xstrdup(fmt("%s-%s", basename, ref));
102 } 103 }
103 104
104 for (f = cgit_snapshot_formats; f->suffix; f++) { 105 for (f = cgit_snapshot_formats; f->suffix; f++) {
105 if (!(repo->snapshots & f->bit)) 106 if (!(repo->snapshots & f->bit))
106 continue; 107 continue;
107 filename = fmt("%s%s", ref, f->suffix); 108 filename = fmt("%s%s", ref, f->suffix);
108 cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename); 109 cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename);
109 html("&nbsp;&nbsp;"); 110 html("&nbsp;&nbsp;");
110 } 111 }
111} 112}
112static int print_tag(struct refinfo *ref) 113static int print_tag(struct refinfo *ref)
113{ 114{
114 struct tag *tag; 115 struct tag *tag;
115 struct taginfo *info; 116 struct taginfo *info;
116 char *name = (char *)ref->refname; 117 char *name = (char *)ref->refname;
117 118
118 if (ref->object->type == OBJ_TAG) { 119 if (ref->object->type == OBJ_TAG) {
119 tag = (struct tag *)ref->object; 120 tag = (struct tag *)ref->object;
120 info = ref->tag; 121 info = ref->tag;
121 if (!tag || !info) 122 if (!tag || !info)
122 return 1; 123 return 1;
123 html("<tr><td>"); 124 html("<tr><td>");
124 cgit_tag_link(name, NULL, NULL, ctx.qry.head, name); 125 cgit_tag_link(name, NULL, NULL, ctx.qry.head, name);
125 html("</td><td>"); 126 html("</td><td>");
diff --git a/ui-repolist.c b/ui-repolist.c
index 87196f0..2c13d50 100644
--- a/ui-repolist.c
+++ b/ui-repolist.c
@@ -196,83 +196,83 @@ int sort_repolist(char *field)
196 } 196 }
197 return 0; 197 return 0;
198} 198}
199 199
200 200
201void cgit_print_repolist() 201void cgit_print_repolist()
202{ 202{
203 int i, columns = 4, hits = 0, header = 0; 203 int i, columns = 4, hits = 0, header = 0;
204 char *last_group = NULL; 204 char *last_group = NULL;
205 int sorted = 0; 205 int sorted = 0;
206 206
207 if (ctx.cfg.enable_index_links) 207 if (ctx.cfg.enable_index_links)
208 columns++; 208 columns++;
209 209
210 ctx.page.title = ctx.cfg.root_title; 210 ctx.page.title = ctx.cfg.root_title;
211 cgit_print_http_headers(&ctx); 211 cgit_print_http_headers(&ctx);
212 cgit_print_docstart(&ctx); 212 cgit_print_docstart(&ctx);
213 cgit_print_pageheader(&ctx); 213 cgit_print_pageheader(&ctx);
214 214
215 if (ctx.cfg.index_header) 215 if (ctx.cfg.index_header)
216 html_include(ctx.cfg.index_header); 216 html_include(ctx.cfg.index_header);
217 217
218 if(ctx.qry.sort) 218 if(ctx.qry.sort)
219 sorted = sort_repolist(ctx.qry.sort); 219 sorted = sort_repolist(ctx.qry.sort);
220 220
221 html("<table summary='repository list' class='list nowrap'>"); 221 html("<table summary='repository list' class='list nowrap'>");
222 for (i=0; i<cgit_repolist.count; i++) { 222 for (i=0; i<cgit_repolist.count; i++) {
223 ctx.repo = &cgit_repolist.repos[i]; 223 ctx.repo = &cgit_repolist.repos[i];
224 if (!(is_match(ctx.repo) && is_in_url(ctx.repo))) 224 if (!(is_match(ctx.repo) && is_in_url(ctx.repo)))
225 continue; 225 continue;
226 hits++; 226 hits++;
227 if (hits <= ctx.qry.ofs) 227 if (hits <= ctx.qry.ofs)
228 continue; 228 continue;
229 if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count) 229 if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count)
230 continue; 230 continue;
231 if (!header++) 231 if (!header++)
232 print_header(columns); 232 print_header(columns);
233 if (!sorted && 233 if (!sorted &&
234 ((last_group == NULL && ctx.repo->group != NULL) || 234 ((last_group == NULL && ctx.repo->group != NULL) ||
235 (last_group != NULL && ctx.repo->group == NULL) || 235 (last_group != NULL && ctx.repo->group == NULL) ||
236 (last_group != NULL && ctx.repo->group != NULL && 236 (last_group != NULL && ctx.repo->group != NULL &&
237 strcmp(ctx.repo->group, last_group)))) { 237 strcmp(ctx.repo->group, last_group)))) {
238 htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>", 238 htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>",
239 columns); 239 columns);
240 html_txt(ctx.repo->group); 240 html_txt(ctx.repo->group);
241 html("</td></tr>"); 241 html("</td></tr>");
242 last_group = ctx.repo->group; 242 last_group = ctx.repo->group;
243 } 243 }
244 htmlf("<tr><td class='%s'>", 244 htmlf("<tr><td class='%s'>",
245 !sorted && ctx.repo->group ? "sublevel-repo" : "toplevel-repo"); 245 !sorted && ctx.repo->group ? "sublevel-repo" : "toplevel-repo");
246 cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); 246 cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL);
247 html("</td><td>"); 247 html("</td><td>");
248 html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL); 248 html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL);
249 html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc); 249 html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc);
250 html_link_close(); 250 html_link_close();
251 html("</td><td>"); 251 html("</td><td>");
252 html_txt(ctx.repo->owner); 252 html_txt(ctx.repo->owner);
253 html("</td><td>"); 253 html("</td><td>");
254 print_modtime(ctx.repo); 254 print_modtime(ctx.repo);
255 html("</td>"); 255 html("</td>");
256 if (ctx.cfg.enable_index_links) { 256 if (ctx.cfg.enable_index_links) {
257 html("<td>"); 257 html("<td>");
258 cgit_summary_link("summary", NULL, "button", NULL); 258 cgit_summary_link("summary", NULL, "button", NULL);
259 cgit_log_link("log", NULL, "button", NULL, NULL, NULL, 259 cgit_log_link("log", NULL, "button", NULL, NULL, NULL,
260 0, NULL, NULL); 260 0, NULL, NULL, ctx.qry.showmsg);
261 cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); 261 cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL);
262 html("</td>"); 262 html("</td>");
263 } 263 }
264 html("</tr>\n"); 264 html("</tr>\n");
265 } 265 }
266 html("</table>"); 266 html("</table>");
267 if (!hits) 267 if (!hits)
268 cgit_print_error("No repositories found"); 268 cgit_print_error("No repositories found");
269 else if (hits > ctx.cfg.max_repo_count) 269 else if (hits > ctx.cfg.max_repo_count)
270 print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search); 270 print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search);
271 cgit_print_docend(); 271 cgit_print_docend();
272} 272}
273 273
274void cgit_print_site_readme() 274void cgit_print_site_readme()
275{ 275{
276 if (ctx.cfg.root_readme) 276 if (ctx.cfg.root_readme)
277 html_include(ctx.cfg.root_readme); 277 html_include(ctx.cfg.root_readme);
278} 278}
diff --git a/ui-shared.c b/ui-shared.c
index 9319881..95dfeb4 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -220,152 +220,158 @@ static char *repolink(char *title, char *class, char *page, char *head,
220 } 220 }
221 } else { 221 } else {
222 html(ctx.cfg.script_name); 222 html(ctx.cfg.script_name);
223 html("?url="); 223 html("?url=");
224 html_url_arg(ctx.repo->url); 224 html_url_arg(ctx.repo->url);
225 if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') 225 if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')
226 html("/"); 226 html("/");
227 if (page) { 227 if (page) {
228 html_url_arg(page); 228 html_url_arg(page);
229 html("/"); 229 html("/");
230 if (path) 230 if (path)
231 html_url_arg(path); 231 html_url_arg(path);
232 } 232 }
233 delim = "&amp;"; 233 delim = "&amp;";
234 } 234 }
235 if (head && strcmp(head, ctx.repo->defbranch)) { 235 if (head && strcmp(head, ctx.repo->defbranch)) {
236 html(delim); 236 html(delim);
237 html("h="); 237 html("h=");
238 html_url_arg(head); 238 html_url_arg(head);
239 delim = "&amp;"; 239 delim = "&amp;";
240 } 240 }
241 return fmt("%s", delim); 241 return fmt("%s", delim);
242} 242}
243 243
244static void reporevlink(char *page, char *name, char *title, char *class, 244static void reporevlink(char *page, char *name, char *title, char *class,
245 char *head, char *rev, char *path) 245 char *head, char *rev, char *path)
246{ 246{
247 char *delim; 247 char *delim;
248 248
249 delim = repolink(title, class, page, head, path); 249 delim = repolink(title, class, page, head, path);
250 if (rev && strcmp(rev, ctx.qry.head)) { 250 if (rev && strcmp(rev, ctx.qry.head)) {
251 html(delim); 251 html(delim);
252 html("id="); 252 html("id=");
253 html_url_arg(rev); 253 html_url_arg(rev);
254 } 254 }
255 html("'>"); 255 html("'>");
256 html_txt(name); 256 html_txt(name);
257 html("</a>"); 257 html("</a>");
258} 258}
259 259
260void cgit_summary_link(char *name, char *title, char *class, char *head) 260void cgit_summary_link(char *name, char *title, char *class, char *head)
261{ 261{
262 reporevlink(NULL, name, title, class, head, NULL, NULL); 262 reporevlink(NULL, name, title, class, head, NULL, NULL);
263} 263}
264 264
265void cgit_tag_link(char *name, char *title, char *class, char *head, 265void cgit_tag_link(char *name, char *title, char *class, char *head,
266 char *rev) 266 char *rev)
267{ 267{
268 reporevlink("tag", name, title, class, head, rev, NULL); 268 reporevlink("tag", name, title, class, head, rev, NULL);
269} 269}
270 270
271void cgit_tree_link(char *name, char *title, char *class, char *head, 271void cgit_tree_link(char *name, char *title, char *class, char *head,
272 char *rev, char *path) 272 char *rev, char *path)
273{ 273{
274 reporevlink("tree", name, title, class, head, rev, path); 274 reporevlink("tree", name, title, class, head, rev, path);
275} 275}
276 276
277void cgit_plain_link(char *name, char *title, char *class, char *head, 277void cgit_plain_link(char *name, char *title, char *class, char *head,
278 char *rev, char *path) 278 char *rev, char *path)
279{ 279{
280 reporevlink("plain", name, title, class, head, rev, path); 280 reporevlink("plain", name, title, class, head, rev, path);
281} 281}
282 282
283void cgit_log_link(char *name, char *title, char *class, char *head, 283void cgit_log_link(char *name, char *title, char *class, char *head,
284 char *rev, char *path, int ofs, char *grep, char *pattern) 284 char *rev, char *path, int ofs, char *grep, char *pattern,
285 int showmsg)
285{ 286{
286 char *delim; 287 char *delim;
287 288
288 delim = repolink(title, class, "log", head, path); 289 delim = repolink(title, class, "log", head, path);
289 if (rev && strcmp(rev, ctx.qry.head)) { 290 if (rev && strcmp(rev, ctx.qry.head)) {
290 html(delim); 291 html(delim);
291 html("id="); 292 html("id=");
292 html_url_arg(rev); 293 html_url_arg(rev);
293 delim = "&"; 294 delim = "&";
294 } 295 }
295 if (grep && pattern) { 296 if (grep && pattern) {
296 html(delim); 297 html(delim);
297 html("qt="); 298 html("qt=");
298 html_url_arg(grep); 299 html_url_arg(grep);
299 delim = "&"; 300 delim = "&";
300 html(delim); 301 html(delim);
301 html("q="); 302 html("q=");
302 html_url_arg(pattern); 303 html_url_arg(pattern);
303 } 304 }
304 if (ofs > 0) { 305 if (ofs > 0) {
305 html(delim); 306 html(delim);
306 html("ofs="); 307 html("ofs=");
307 htmlf("%d", ofs); 308 htmlf("%d", ofs);
309 delim = "&";
310 }
311 if (showmsg) {
312 html(delim);
313 html("showmsg=1");
308 } 314 }
309 html("'>"); 315 html("'>");
310 html_txt(name); 316 html_txt(name);
311 html("</a>"); 317 html("</a>");
312} 318}
313 319
314void cgit_commit_link(char *name, char *title, char *class, char *head, 320void cgit_commit_link(char *name, char *title, char *class, char *head,
315 char *rev) 321 char *rev)
316{ 322{
317 if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { 323 if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) {
318 name[ctx.cfg.max_msg_len] = '\0'; 324 name[ctx.cfg.max_msg_len] = '\0';
319 name[ctx.cfg.max_msg_len - 1] = '.'; 325 name[ctx.cfg.max_msg_len - 1] = '.';
320 name[ctx.cfg.max_msg_len - 2] = '.'; 326 name[ctx.cfg.max_msg_len - 2] = '.';
321 name[ctx.cfg.max_msg_len - 3] = '.'; 327 name[ctx.cfg.max_msg_len - 3] = '.';
322 } 328 }
323 reporevlink("commit", name, title, class, head, rev, NULL); 329 reporevlink("commit", name, title, class, head, rev, NULL);
324} 330}
325 331
326void cgit_refs_link(char *name, char *title, char *class, char *head, 332void cgit_refs_link(char *name, char *title, char *class, char *head,
327 char *rev, char *path) 333 char *rev, char *path)
328{ 334{
329 reporevlink("refs", name, title, class, head, rev, path); 335 reporevlink("refs", name, title, class, head, rev, path);
330} 336}
331 337
332void cgit_snapshot_link(char *name, char *title, char *class, char *head, 338void cgit_snapshot_link(char *name, char *title, char *class, char *head,
333 char *rev, char *archivename) 339 char *rev, char *archivename)
334{ 340{
335 reporevlink("snapshot", name, title, class, head, rev, archivename); 341 reporevlink("snapshot", name, title, class, head, rev, archivename);
336} 342}
337 343
338void cgit_diff_link(char *name, char *title, char *class, char *head, 344void cgit_diff_link(char *name, char *title, char *class, char *head,
339 char *new_rev, char *old_rev, char *path) 345 char *new_rev, char *old_rev, char *path)
340{ 346{
341 char *delim; 347 char *delim;
342 348
343 delim = repolink(title, class, "diff", head, path); 349 delim = repolink(title, class, "diff", head, path);
344 if (new_rev && strcmp(new_rev, ctx.qry.head)) { 350 if (new_rev && strcmp(new_rev, ctx.qry.head)) {
345 html(delim); 351 html(delim);
346 html("id="); 352 html("id=");
347 html_url_arg(new_rev); 353 html_url_arg(new_rev);
348 delim = "&amp;"; 354 delim = "&amp;";
349 } 355 }
350 if (old_rev) { 356 if (old_rev) {
351 html(delim); 357 html(delim);
352 html("id2="); 358 html("id2=");
353 html_url_arg(old_rev); 359 html_url_arg(old_rev);
354 } 360 }
355 html("'>"); 361 html("'>");
356 html_txt(name); 362 html_txt(name);
357 html("</a>"); 363 html("</a>");
358} 364}
359 365
360void cgit_patch_link(char *name, char *title, char *class, char *head, 366void cgit_patch_link(char *name, char *title, char *class, char *head,
361 char *rev) 367 char *rev)
362{ 368{
363 reporevlink("patch", name, title, class, head, rev, NULL); 369 reporevlink("patch", name, title, class, head, rev, NULL);
364} 370}
365 371
366void cgit_object_link(struct object *obj) 372void cgit_object_link(struct object *obj)
367{ 373{
368 char *page, *shortrev, *fullrev, *name; 374 char *page, *shortrev, *fullrev, *name;
369 375
370 fullrev = sha1_to_hex(obj->sha1); 376 fullrev = sha1_to_hex(obj->sha1);
371 shortrev = xstrdup(fullrev); 377 shortrev = xstrdup(fullrev);
@@ -509,195 +515,197 @@ int print_branch_option(const char *refname, const unsigned char *sha1,
509{ 515{
510 char *name = (char *)refname; 516 char *name = (char *)refname;
511 html_option(name, name, ctx.qry.head); 517 html_option(name, name, ctx.qry.head);
512 return 0; 518 return 0;
513} 519}
514 520
515int print_archive_ref(const char *refname, const unsigned char *sha1, 521int print_archive_ref(const char *refname, const unsigned char *sha1,
516 int flags, void *cb_data) 522 int flags, void *cb_data)
517{ 523{
518 struct tag *tag; 524 struct tag *tag;
519 struct taginfo *info; 525 struct taginfo *info;
520 struct object *obj; 526 struct object *obj;
521 char buf[256], *url; 527 char buf[256], *url;
522 unsigned char fileid[20]; 528 unsigned char fileid[20];
523 int *header = (int *)cb_data; 529 int *header = (int *)cb_data;
524 530
525 if (prefixcmp(refname, "refs/archives")) 531 if (prefixcmp(refname, "refs/archives"))
526 return 0; 532 return 0;
527 strncpy(buf, refname+14, sizeof(buf)); 533 strncpy(buf, refname+14, sizeof(buf));
528 obj = parse_object(sha1); 534 obj = parse_object(sha1);
529 if (!obj) 535 if (!obj)
530 return 1; 536 return 1;
531 if (obj->type == OBJ_TAG) { 537 if (obj->type == OBJ_TAG) {
532 tag = lookup_tag(sha1); 538 tag = lookup_tag(sha1);
533 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 539 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
534 return 0; 540 return 0;
535 hashcpy(fileid, tag->tagged->sha1); 541 hashcpy(fileid, tag->tagged->sha1);
536 } else if (obj->type != OBJ_BLOB) { 542 } else if (obj->type != OBJ_BLOB) {
537 return 0; 543 return 0;
538 } else { 544 } else {
539 hashcpy(fileid, sha1); 545 hashcpy(fileid, sha1);
540 } 546 }
541 if (!*header) { 547 if (!*header) {
542 html("<h1>download</h1>\n"); 548 html("<h1>download</h1>\n");
543 *header = 1; 549 *header = 1;
544 } 550 }
545 url = cgit_pageurl(ctx.qry.repo, "blob", 551 url = cgit_pageurl(ctx.qry.repo, "blob",
546 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid), 552 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid),
547 buf)); 553 buf));
548 html_link_open(url, NULL, "menu"); 554 html_link_open(url, NULL, "menu");
549 html_txt(strlpart(buf, 20)); 555 html_txt(strlpart(buf, 20));
550 html_link_close(); 556 html_link_close();
551 return 0; 557 return 0;
552} 558}
553 559
554void add_hidden_formfields(int incl_head, int incl_search, char *page) 560void add_hidden_formfields(int incl_head, int incl_search, char *page)
555{ 561{
556 char *url; 562 char *url;
557 563
558 if (!ctx.cfg.virtual_root) { 564 if (!ctx.cfg.virtual_root) {
559 url = fmt("%s/%s", ctx.qry.repo, page); 565 url = fmt("%s/%s", ctx.qry.repo, page);
560 if (ctx.qry.path) 566 if (ctx.qry.path)
561 url = fmt("%s/%s", url, ctx.qry.path); 567 url = fmt("%s/%s", url, ctx.qry.path);
562 html_hidden("url", url); 568 html_hidden("url", url);
563 } 569 }
564 570
565 if (incl_head && ctx.qry.head && ctx.repo->defbranch && 571 if (incl_head && ctx.qry.head && ctx.repo->defbranch &&
566 strcmp(ctx.qry.head, ctx.repo->defbranch)) 572 strcmp(ctx.qry.head, ctx.repo->defbranch))
567 html_hidden("h", ctx.qry.head); 573 html_hidden("h", ctx.qry.head);
568 574
569 if (ctx.qry.sha1) 575 if (ctx.qry.sha1)
570 html_hidden("id", ctx.qry.sha1); 576 html_hidden("id", ctx.qry.sha1);
571 if (ctx.qry.sha2) 577 if (ctx.qry.sha2)
572 html_hidden("id2", ctx.qry.sha2); 578 html_hidden("id2", ctx.qry.sha2);
579 if (ctx.qry.showmsg)
580 html_hidden("showmsg", "1");
573 581
574 if (incl_search) { 582 if (incl_search) {
575 if (ctx.qry.grep) 583 if (ctx.qry.grep)
576 html_hidden("qt", ctx.qry.grep); 584 html_hidden("qt", ctx.qry.grep);
577 if (ctx.qry.search) 585 if (ctx.qry.search)
578 html_hidden("q", ctx.qry.search); 586 html_hidden("q", ctx.qry.search);
579 } 587 }
580} 588}
581 589
582char *hc(struct cgit_cmd *cmd, const char *page) 590char *hc(struct cgit_cmd *cmd, const char *page)
583{ 591{
584 return (strcmp(cmd->name, page) ? NULL : "active"); 592 return (strcmp(cmd->name, page) ? NULL : "active");
585} 593}
586 594
587void cgit_print_pageheader(struct cgit_context *ctx) 595void cgit_print_pageheader(struct cgit_context *ctx)
588{ 596{
589 struct cgit_cmd *cmd = cgit_get_cmd(ctx); 597 struct cgit_cmd *cmd = cgit_get_cmd(ctx);
590 598
591 html("<table id='header'>\n"); 599 html("<table id='header'>\n");
592 html("<tr>\n"); 600 html("<tr>\n");
593 html("<td class='logo' rowspan='2'><a href='"); 601 html("<td class='logo' rowspan='2'><a href='");
594 if (ctx->cfg.logo_link) 602 if (ctx->cfg.logo_link)
595 html_attr(ctx->cfg.logo_link); 603 html_attr(ctx->cfg.logo_link);
596 else 604 else
597 html_attr(cgit_rooturl()); 605 html_attr(cgit_rooturl());
598 html("'><img src='"); 606 html("'><img src='");
599 html_attr(ctx->cfg.logo); 607 html_attr(ctx->cfg.logo);
600 html("' alt='cgit logo'/></a></td>\n"); 608 html("' alt='cgit logo'/></a></td>\n");
601 609
602 html("<td class='main'>"); 610 html("<td class='main'>");
603 if (ctx->repo) { 611 if (ctx->repo) {
604 cgit_index_link("index", NULL, NULL, NULL, 0); 612 cgit_index_link("index", NULL, NULL, NULL, 0);
605 html(" : "); 613 html(" : ");
606 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); 614 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL);
607 html("</td><td class='form'>"); 615 html("</td><td class='form'>");
608 html("<form method='get' action=''>\n"); 616 html("<form method='get' action=''>\n");
609 add_hidden_formfields(0, 1, ctx->qry.page); 617 add_hidden_formfields(0, 1, ctx->qry.page);
610 html("<select name='h' onchange='this.form.submit();'>\n"); 618 html("<select name='h' onchange='this.form.submit();'>\n");
611 for_each_branch_ref(print_branch_option, ctx->qry.head); 619 for_each_branch_ref(print_branch_option, ctx->qry.head);
612 html("</select> "); 620 html("</select> ");
613 html("<input type='submit' name='' value='switch'/>"); 621 html("<input type='submit' name='' value='switch'/>");
614 html("</form>"); 622 html("</form>");
615 } else 623 } else
616 html_txt(ctx->cfg.root_title); 624 html_txt(ctx->cfg.root_title);
617 html("</td></tr>\n"); 625 html("</td></tr>\n");
618 626
619 html("<tr><td class='sub'>"); 627 html("<tr><td class='sub'>");
620 if (ctx->repo) { 628 if (ctx->repo) {
621 html_txt(ctx->repo->desc); 629 html_txt(ctx->repo->desc);
622 html("</td><td class='sub right'>"); 630 html("</td><td class='sub right'>");
623 html_txt(ctx->repo->owner); 631 html_txt(ctx->repo->owner);
624 } else { 632 } else {
625 if (ctx->cfg.root_desc) 633 if (ctx->cfg.root_desc)
626 html_txt(ctx->cfg.root_desc); 634 html_txt(ctx->cfg.root_desc);
627 else if (ctx->cfg.index_info) 635 else if (ctx->cfg.index_info)
628 html_include(ctx->cfg.index_info); 636 html_include(ctx->cfg.index_info);
629 } 637 }
630 html("</td></tr></table>\n"); 638 html("</td></tr></table>\n");
631 639
632 html("<table class='tabs'><tr><td>\n"); 640 html("<table class='tabs'><tr><td>\n");
633 if (ctx->repo) { 641 if (ctx->repo) {
634 cgit_summary_link("summary", NULL, hc(cmd, "summary"), 642 cgit_summary_link("summary", NULL, hc(cmd, "summary"),
635 ctx->qry.head); 643 ctx->qry.head);
636 cgit_refs_link("refs", NULL, hc(cmd, "refs"), ctx->qry.head, 644 cgit_refs_link("refs", NULL, hc(cmd, "refs"), ctx->qry.head,
637 ctx->qry.sha1, NULL); 645 ctx->qry.sha1, NULL);
638 cgit_log_link("log", NULL, hc(cmd, "log"), ctx->qry.head, 646 cgit_log_link("log", NULL, hc(cmd, "log"), ctx->qry.head,
639 NULL, NULL, 0, NULL, NULL); 647 NULL, NULL, 0, NULL, NULL, ctx->qry.showmsg);
640 cgit_tree_link("tree", NULL, hc(cmd, "tree"), ctx->qry.head, 648 cgit_tree_link("tree", NULL, hc(cmd, "tree"), ctx->qry.head,
641 ctx->qry.sha1, NULL); 649 ctx->qry.sha1, NULL);
642 cgit_commit_link("commit", NULL, hc(cmd, "commit"), 650 cgit_commit_link("commit", NULL, hc(cmd, "commit"),
643 ctx->qry.head, ctx->qry.sha1); 651 ctx->qry.head, ctx->qry.sha1);
644 cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head, 652 cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head,
645 ctx->qry.sha1, ctx->qry.sha2, NULL); 653 ctx->qry.sha1, ctx->qry.sha2, NULL);
646 if (ctx->repo->readme) 654 if (ctx->repo->readme)
647 reporevlink("about", "about", NULL, 655 reporevlink("about", "about", NULL,
648 hc(cmd, "about"), ctx->qry.head, NULL, 656 hc(cmd, "about"), ctx->qry.head, NULL,
649 NULL); 657 NULL);
650 html("</td><td class='form'>"); 658 html("</td><td class='form'>");
651 html("<form class='right' method='get' action='"); 659 html("<form class='right' method='get' action='");
652 if (ctx->cfg.virtual_root) 660 if (ctx->cfg.virtual_root)
653 html_url_path(cgit_fileurl(ctx->qry.repo, "log", 661 html_url_path(cgit_fileurl(ctx->qry.repo, "log",
654 ctx->qry.path, NULL)); 662 ctx->qry.path, NULL));
655 html("'>\n"); 663 html("'>\n");
656 add_hidden_formfields(1, 0, "log"); 664 add_hidden_formfields(1, 0, "log");
657 html("<select name='qt'>\n"); 665 html("<select name='qt'>\n");
658 html_option("grep", "log msg", ctx->qry.grep); 666 html_option("grep", "log msg", ctx->qry.grep);
659 html_option("author", "author", ctx->qry.grep); 667 html_option("author", "author", ctx->qry.grep);
660 html_option("committer", "committer", ctx->qry.grep); 668 html_option("committer", "committer", ctx->qry.grep);
661 html("</select>\n"); 669 html("</select>\n");
662 html("<input class='txt' type='text' size='10' name='q' value='"); 670 html("<input class='txt' type='text' size='10' name='q' value='");
663 html_attr(ctx->qry.search); 671 html_attr(ctx->qry.search);
664 html("'/>\n"); 672 html("'/>\n");
665 html("<input type='submit' value='search'/>\n"); 673 html("<input type='submit' value='search'/>\n");
666 html("</form>\n"); 674 html("</form>\n");
667 } else { 675 } else {
668 site_link(NULL, "index", NULL, hc(cmd, "repolist"), NULL, 0); 676 site_link(NULL, "index", NULL, hc(cmd, "repolist"), NULL, 0);
669 if (ctx->cfg.root_readme) 677 if (ctx->cfg.root_readme)
670 site_link("about", "about", NULL, hc(cmd, "about"), 678 site_link("about", "about", NULL, hc(cmd, "about"),
671 NULL, 0); 679 NULL, 0);
672 html("</td><td class='form'>"); 680 html("</td><td class='form'>");
673 html("<form method='get' action='"); 681 html("<form method='get' action='");
674 html_attr(cgit_rooturl()); 682 html_attr(cgit_rooturl());
675 html("'>\n"); 683 html("'>\n");
676 html("<input type='text' name='q' size='10' value='"); 684 html("<input type='text' name='q' size='10' value='");
677 html_attr(ctx->qry.search); 685 html_attr(ctx->qry.search);
678 html("'/>\n"); 686 html("'/>\n");
679 html("<input type='submit' value='search'/>\n"); 687 html("<input type='submit' value='search'/>\n");
680 html("</form>"); 688 html("</form>");
681 } 689 }
682 html("</td></tr></table>\n"); 690 html("</td></tr></table>\n");
683 html("<div class='content'>"); 691 html("<div class='content'>");
684} 692}
685 693
686void cgit_print_filemode(unsigned short mode) 694void cgit_print_filemode(unsigned short mode)
687{ 695{
688 if (S_ISDIR(mode)) 696 if (S_ISDIR(mode))
689 html("d"); 697 html("d");
690 else if (S_ISLNK(mode)) 698 else if (S_ISLNK(mode))
691 html("l"); 699 html("l");
692 else if (S_ISGITLINK(mode)) 700 else if (S_ISGITLINK(mode))
693 html("m"); 701 html("m");
694 else 702 else
695 html("-"); 703 html("-");
696 html_fileperm(mode >> 6); 704 html_fileperm(mode >> 6);
697 html_fileperm(mode >> 3); 705 html_fileperm(mode >> 3);
698 html_fileperm(mode); 706 html_fileperm(mode);
699} 707}
700 708
701void cgit_print_snapshot_links(const char *repo, const char *head, 709void cgit_print_snapshot_links(const char *repo, const char *head,
702 const char *hex, int snapshots) 710 const char *hex, int snapshots)
703{ 711{
diff --git a/ui-shared.h b/ui-shared.h
index 3c8a6d0..2ab53ae 100644
--- a/ui-shared.h
+++ b/ui-shared.h
@@ -1,46 +1,46 @@
1#ifndef UI_SHARED_H 1#ifndef UI_SHARED_H
2#define UI_SHARED_H 2#define UI_SHARED_H
3 3
4extern char *cgit_hosturl(); 4extern char *cgit_hosturl();
5extern char *cgit_repourl(const char *reponame); 5extern char *cgit_repourl(const char *reponame);
6extern char *cgit_fileurl(const char *reponame, const char *pagename, 6extern char *cgit_fileurl(const char *reponame, const char *pagename,
7 const char *filename, const char *query); 7 const char *filename, const char *query);
8extern char *cgit_pageurl(const char *reponame, const char *pagename, 8extern char *cgit_pageurl(const char *reponame, const char *pagename,
9 const char *query); 9 const char *query);
10 10
11extern void cgit_index_link(char *name, char *title, char *class, 11extern void cgit_index_link(char *name, char *title, char *class,
12 char *pattern, int ofs); 12 char *pattern, int ofs);
13extern void cgit_summary_link(char *name, char *title, char *class, char *head); 13extern void cgit_summary_link(char *name, char *title, char *class, char *head);
14extern void cgit_tag_link(char *name, char *title, char *class, char *head, 14extern void cgit_tag_link(char *name, char *title, char *class, char *head,
15 char *rev); 15 char *rev);
16extern void cgit_tree_link(char *name, char *title, char *class, char *head, 16extern void cgit_tree_link(char *name, char *title, char *class, char *head,
17 char *rev, char *path); 17 char *rev, char *path);
18extern void cgit_plain_link(char *name, char *title, char *class, char *head, 18extern void cgit_plain_link(char *name, char *title, char *class, char *head,
19 char *rev, char *path); 19 char *rev, char *path);
20extern void cgit_log_link(char *name, char *title, char *class, char *head, 20extern void cgit_log_link(char *name, char *title, char *class, char *head,
21 char *rev, char *path, int ofs, char *grep, 21 char *rev, char *path, int ofs, char *grep,
22 char *pattern); 22 char *pattern, int showmsg);
23extern void cgit_commit_link(char *name, char *title, char *class, char *head, 23extern void cgit_commit_link(char *name, char *title, char *class, char *head,
24 char *rev); 24 char *rev);
25extern void cgit_patch_link(char *name, char *title, char *class, char *head, 25extern void cgit_patch_link(char *name, char *title, char *class, char *head,
26 char *rev); 26 char *rev);
27extern void cgit_refs_link(char *name, char *title, char *class, char *head, 27extern void cgit_refs_link(char *name, char *title, char *class, char *head,
28 char *rev, char *path); 28 char *rev, char *path);
29extern void cgit_snapshot_link(char *name, char *title, char *class, 29extern void cgit_snapshot_link(char *name, char *title, char *class,
30 char *head, char *rev, char *archivename); 30 char *head, char *rev, char *archivename);
31extern void cgit_diff_link(char *name, char *title, char *class, char *head, 31extern void cgit_diff_link(char *name, char *title, char *class, char *head,
32 char *new_rev, char *old_rev, char *path); 32 char *new_rev, char *old_rev, char *path);
33extern void cgit_object_link(struct object *obj); 33extern void cgit_object_link(struct object *obj);
34 34
35extern void cgit_print_error(char *msg); 35extern void cgit_print_error(char *msg);
36extern void cgit_print_date(time_t secs, char *format, int local_time); 36extern void cgit_print_date(time_t secs, char *format, int local_time);
37extern void cgit_print_age(time_t t, time_t max_relative, char *format); 37extern void cgit_print_age(time_t t, time_t max_relative, char *format);
38extern void cgit_print_http_headers(struct cgit_context *ctx); 38extern void cgit_print_http_headers(struct cgit_context *ctx);
39extern void cgit_print_docstart(struct cgit_context *ctx); 39extern void cgit_print_docstart(struct cgit_context *ctx);
40extern void cgit_print_docend(); 40extern void cgit_print_docend();
41extern void cgit_print_pageheader(struct cgit_context *ctx); 41extern void cgit_print_pageheader(struct cgit_context *ctx);
42extern void cgit_print_filemode(unsigned short mode); 42extern void cgit_print_filemode(unsigned short mode);
43extern void cgit_print_snapshot_links(const char *repo, const char *head, 43extern void cgit_print_snapshot_links(const char *repo, const char *head,
44 const char *hex, int snapshots); 44 const char *hex, int snapshots);
45 45
46#endif /* UI_SHARED_H */ 46#endif /* UI_SHARED_H */
diff --git a/ui-tree.c b/ui-tree.c
index 79332fc..051db7c 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -45,129 +45,129 @@ static void print_object(const unsigned char *sha1, char *path)
45 start = 0; 45 start = 0;
46 lineno = 0; 46 lineno = 0;
47 while(idx < size) { 47 while(idx < size) {
48 if (buf[idx] == '\n') { 48 if (buf[idx] == '\n') {
49 buf[idx] = '\0'; 49 buf[idx] = '\0';
50 htmlf(linefmt, ++lineno); 50 htmlf(linefmt, ++lineno);
51 html_txt(buf + start); 51 html_txt(buf + start);
52 html("</td></tr>\n"); 52 html("</td></tr>\n");
53 start = idx + 1; 53 start = idx + 1;
54 } 54 }
55 idx++; 55 idx++;
56 } 56 }
57 htmlf(linefmt, ++lineno); 57 htmlf(linefmt, ++lineno);
58 html_txt(buf + start); 58 html_txt(buf + start);
59 html("</td></tr>\n"); 59 html("</td></tr>\n");
60 html("</table>\n"); 60 html("</table>\n");
61} 61}
62 62
63 63
64static int ls_item(const unsigned char *sha1, const char *base, int baselen, 64static int ls_item(const unsigned char *sha1, const char *base, int baselen,
65 const char *pathname, unsigned int mode, int stage, 65 const char *pathname, unsigned int mode, int stage,
66 void *cbdata) 66 void *cbdata)
67{ 67{
68 char *name; 68 char *name;
69 char *fullpath; 69 char *fullpath;
70 enum object_type type; 70 enum object_type type;
71 unsigned long size = 0; 71 unsigned long size = 0;
72 72
73 name = xstrdup(pathname); 73 name = xstrdup(pathname);
74 fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", 74 fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "",
75 ctx.qry.path ? "/" : "", name); 75 ctx.qry.path ? "/" : "", name);
76 76
77 if (!S_ISGITLINK(mode)) { 77 if (!S_ISGITLINK(mode)) {
78 type = sha1_object_info(sha1, &size); 78 type = sha1_object_info(sha1, &size);
79 if (type == OBJ_BAD) { 79 if (type == OBJ_BAD) {
80 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", 80 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>",
81 name, 81 name,
82 sha1_to_hex(sha1)); 82 sha1_to_hex(sha1));
83 return 0; 83 return 0;
84 } 84 }
85 } 85 }
86 86
87 html("<tr><td class='ls-mode'>"); 87 html("<tr><td class='ls-mode'>");
88 cgit_print_filemode(mode); 88 cgit_print_filemode(mode);
89 html("</td><td>"); 89 html("</td><td>");
90 if (S_ISGITLINK(mode)) { 90 if (S_ISGITLINK(mode)) {
91 htmlf("<a class='ls-mod' href='"); 91 htmlf("<a class='ls-mod' href='");
92 html_attr(fmt(ctx.repo->module_link, 92 html_attr(fmt(ctx.repo->module_link,
93 name, 93 name,
94 sha1_to_hex(sha1))); 94 sha1_to_hex(sha1)));
95 html("'>"); 95 html("'>");
96 html_txt(name); 96 html_txt(name);
97 html("</a>"); 97 html("</a>");
98 } else if (S_ISDIR(mode)) { 98 } else if (S_ISDIR(mode)) {
99 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, 99 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head,
100 curr_rev, fullpath); 100 curr_rev, fullpath);
101 } else { 101 } else {
102 cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head, 102 cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head,
103 curr_rev, fullpath); 103 curr_rev, fullpath);
104 } 104 }
105 htmlf("</td><td class='ls-size'>%li</td>", size); 105 htmlf("</td><td class='ls-size'>%li</td>", size);
106 106
107 html("<td>"); 107 html("<td>");
108 cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev, 108 cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev,
109 fullpath, 0, NULL, NULL); 109 fullpath, 0, NULL, NULL, ctx.qry.showmsg);
110 html("</td></tr>\n"); 110 html("</td></tr>\n");
111 free(name); 111 free(name);
112 return 0; 112 return 0;
113} 113}
114 114
115static void ls_head() 115static void ls_head()
116{ 116{
117 html("<table summary='tree listing' class='list'>\n"); 117 html("<table summary='tree listing' class='list'>\n");
118 html("<tr class='nohover'>"); 118 html("<tr class='nohover'>");
119 html("<th class='left'>Mode</th>"); 119 html("<th class='left'>Mode</th>");
120 html("<th class='left'>Name</th>"); 120 html("<th class='left'>Name</th>");
121 html("<th class='right'>Size</th>"); 121 html("<th class='right'>Size</th>");
122 html("<th/>"); 122 html("<th/>");
123 html("</tr>\n"); 123 html("</tr>\n");
124 header = 1; 124 header = 1;
125} 125}
126 126
127static void ls_tail() 127static void ls_tail()
128{ 128{
129 if (!header) 129 if (!header)
130 return; 130 return;
131 html("</table>\n"); 131 html("</table>\n");
132 header = 0; 132 header = 0;
133} 133}
134 134
135static void ls_tree(const unsigned char *sha1, char *path) 135static void ls_tree(const unsigned char *sha1, char *path)
136{ 136{
137 struct tree *tree; 137 struct tree *tree;
138 138
139 tree = parse_tree_indirect(sha1); 139 tree = parse_tree_indirect(sha1);
140 if (!tree) { 140 if (!tree) {
141 cgit_print_error(fmt("Not a tree object: %s", 141 cgit_print_error(fmt("Not a tree object: %s",
142 sha1_to_hex(sha1))); 142 sha1_to_hex(sha1)));
143 return; 143 return;
144 } 144 }
145 145
146 ls_head(); 146 ls_head();
147 read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL); 147 read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL);
148 ls_tail(); 148 ls_tail();
149} 149}
150 150
151 151
152static int walk_tree(const unsigned char *sha1, const char *base, int baselen, 152static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
153 const char *pathname, unsigned mode, int stage, 153 const char *pathname, unsigned mode, int stage,
154 void *cbdata) 154 void *cbdata)
155{ 155{
156 static int state; 156 static int state;
157 static char buffer[PATH_MAX]; 157 static char buffer[PATH_MAX];
158 char *url; 158 char *url;
159 159
160 if (state == 0) { 160 if (state == 0) {
161 memcpy(buffer, base, baselen); 161 memcpy(buffer, base, baselen);
162 strcpy(buffer+baselen, pathname); 162 strcpy(buffer+baselen, pathname);
163 url = cgit_pageurl(ctx.qry.repo, "tree", 163 url = cgit_pageurl(ctx.qry.repo, "tree",
164 fmt("h=%s&amp;path=%s", curr_rev, buffer)); 164 fmt("h=%s&amp;path=%s", curr_rev, buffer));
165 html("/"); 165 html("/");
166 cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head, 166 cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head,
167 curr_rev, buffer); 167 curr_rev, buffer);
168 168
169 if (strcmp(match_path, buffer)) 169 if (strcmp(match_path, buffer))
170 return READ_TREE_RECURSIVE; 170 return READ_TREE_RECURSIVE;
171 171
172 if (S_ISDIR(mode)) { 172 if (S_ISDIR(mode)) {
173 state = 1; 173 state = 1;