summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.h8
-rw-r--r--shared.c27
-rw-r--r--ui-shared.c17
-rw-r--r--ui-snapshot.c124
4 files changed, 90 insertions, 86 deletions
diff --git a/cgit.h b/cgit.h
index 295441b..e2d5126 100644
--- a/cgit.h
+++ b/cgit.h
@@ -84,196 +84,204 @@ struct commitinfo {
84 char *committer_email; 84 char *committer_email;
85 unsigned long committer_date; 85 unsigned long committer_date;
86 char *subject; 86 char *subject;
87 char *msg; 87 char *msg;
88 char *msg_encoding; 88 char *msg_encoding;
89}; 89};
90 90
91struct taginfo { 91struct taginfo {
92 char *tagger; 92 char *tagger;
93 char *tagger_email; 93 char *tagger_email;
94 int tagger_date; 94 int tagger_date;
95 char *msg; 95 char *msg;
96}; 96};
97 97
98struct refinfo { 98struct refinfo {
99 const char *refname; 99 const char *refname;
100 struct object *object; 100 struct object *object;
101 union { 101 union {
102 struct taginfo *tag; 102 struct taginfo *tag;
103 struct commitinfo *commit; 103 struct commitinfo *commit;
104 }; 104 };
105}; 105};
106 106
107struct reflist { 107struct reflist {
108 struct refinfo **refs; 108 struct refinfo **refs;
109 int alloc; 109 int alloc;
110 int count; 110 int count;
111}; 111};
112 112
113struct cgit_query { 113struct cgit_query {
114 int has_symref; 114 int has_symref;
115 int has_sha1; 115 int has_sha1;
116 char *raw; 116 char *raw;
117 char *repo; 117 char *repo;
118 char *page; 118 char *page;
119 char *search; 119 char *search;
120 char *grep; 120 char *grep;
121 char *head; 121 char *head;
122 char *sha1; 122 char *sha1;
123 char *sha2; 123 char *sha2;
124 char *path; 124 char *path;
125 char *name; 125 char *name;
126 int ofs; 126 int ofs;
127}; 127};
128 128
129struct cgit_config { 129struct cgit_config {
130 char *agefile; 130 char *agefile;
131 char *cache_root; 131 char *cache_root;
132 char *clone_prefix; 132 char *clone_prefix;
133 char *css; 133 char *css;
134 char *index_header; 134 char *index_header;
135 char *index_info; 135 char *index_info;
136 char *logo; 136 char *logo;
137 char *logo_link; 137 char *logo_link;
138 char *module_link; 138 char *module_link;
139 char *repo_group; 139 char *repo_group;
140 char *robots; 140 char *robots;
141 char *root_title; 141 char *root_title;
142 char *script_name; 142 char *script_name;
143 char *virtual_root; 143 char *virtual_root;
144 int cache_dynamic_ttl; 144 int cache_dynamic_ttl;
145 int cache_max_create_time; 145 int cache_max_create_time;
146 int cache_repo_ttl; 146 int cache_repo_ttl;
147 int cache_root_ttl; 147 int cache_root_ttl;
148 int cache_static_ttl; 148 int cache_static_ttl;
149 int enable_index_links; 149 int enable_index_links;
150 int enable_log_filecount; 150 int enable_log_filecount;
151 int enable_log_linecount; 151 int enable_log_linecount;
152 int max_commit_count; 152 int max_commit_count;
153 int max_lock_attempts; 153 int max_lock_attempts;
154 int max_msg_len; 154 int max_msg_len;
155 int max_repodesc_len; 155 int max_repodesc_len;
156 int nocache; 156 int nocache;
157 int renamelimit; 157 int renamelimit;
158 int snapshots; 158 int snapshots;
159 int summary_branches; 159 int summary_branches;
160 int summary_log; 160 int summary_log;
161 int summary_tags; 161 int summary_tags;
162}; 162};
163 163
164struct cgit_page { 164struct cgit_page {
165 time_t modified; 165 time_t modified;
166 time_t expires; 166 time_t expires;
167 char *mimetype; 167 char *mimetype;
168 char *charset; 168 char *charset;
169 char *filename; 169 char *filename;
170 char *title; 170 char *title;
171}; 171};
172 172
173struct cgit_context { 173struct cgit_context {
174 struct cgit_query qry; 174 struct cgit_query qry;
175 struct cgit_config cfg; 175 struct cgit_config cfg;
176 struct cgit_repo *repo; 176 struct cgit_repo *repo;
177 struct cgit_page page; 177 struct cgit_page page;
178}; 178};
179 179
180struct cgit_snapshot_format {
181 const char *suffix;
182 const char *mimetype;
183 write_archive_fn_t write_func;
184 int bit;
185};
186
180extern const char *cgit_version; 187extern const char *cgit_version;
181 188
182extern struct cgit_repolist cgit_repolist; 189extern struct cgit_repolist cgit_repolist;
183extern struct cgit_context ctx; 190extern struct cgit_context ctx;
191extern const struct cgit_snapshot_format cgit_snapshot_formats[];
184extern int cgit_cmd; 192extern int cgit_cmd;
185 193
186extern void cgit_prepare_context(struct cgit_context *ctx); 194extern void cgit_prepare_context(struct cgit_context *ctx);
187extern struct cgit_repo *cgit_get_repoinfo(const char *url); 195extern struct cgit_repo *cgit_get_repoinfo(const char *url);
188extern void cgit_global_config_cb(const char *name, const char *value); 196extern void cgit_global_config_cb(const char *name, const char *value);
189extern void cgit_repo_config_cb(const char *name, const char *value); 197extern void cgit_repo_config_cb(const char *name, const char *value);
190extern void cgit_querystring_cb(const char *name, const char *value); 198extern void cgit_querystring_cb(const char *name, const char *value);
191 199
192extern int chk_zero(int result, char *msg); 200extern int chk_zero(int result, char *msg);
193extern int chk_positive(int result, char *msg); 201extern int chk_positive(int result, char *msg);
194extern int chk_non_negative(int result, char *msg); 202extern int chk_non_negative(int result, char *msg);
195 203
196extern int hextoint(char c); 204extern int hextoint(char c);
197extern char *trim_end(const char *str, char c); 205extern char *trim_end(const char *str, char c);
198extern char *strlpart(char *txt, int maxlen); 206extern char *strlpart(char *txt, int maxlen);
199extern char *strrpart(char *txt, int maxlen); 207extern char *strrpart(char *txt, int maxlen);
200 208
201extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); 209extern void cgit_add_ref(struct reflist *list, struct refinfo *ref);
202extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, 210extern int cgit_refs_cb(const char *refname, const unsigned char *sha1,
203 int flags, void *cb_data); 211 int flags, void *cb_data);
204 212
205extern void *cgit_free_commitinfo(struct commitinfo *info); 213extern void *cgit_free_commitinfo(struct commitinfo *info);
206 214
207extern int cgit_diff_files(const unsigned char *old_sha1, 215extern int cgit_diff_files(const unsigned char *old_sha1,
208 const unsigned char *new_sha1, 216 const unsigned char *new_sha1,
209 linediff_fn fn); 217 linediff_fn fn);
210 218
211extern void cgit_diff_tree(const unsigned char *old_sha1, 219extern void cgit_diff_tree(const unsigned char *old_sha1,
212 const unsigned char *new_sha1, 220 const unsigned char *new_sha1,
213 filepair_fn fn, const char *prefix); 221 filepair_fn fn, const char *prefix);
214 222
215extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 223extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
216 224
217extern char *fmt(const char *format,...); 225extern char *fmt(const char *format,...);
218 226
219extern int cgit_read_config(const char *filename, configfn fn); 227extern int cgit_read_config(const char *filename, configfn fn);
220extern int cgit_parse_query(char *txt, configfn fn); 228extern int cgit_parse_query(char *txt, configfn fn);
221extern struct commitinfo *cgit_parse_commit(struct commit *commit); 229extern struct commitinfo *cgit_parse_commit(struct commit *commit);
222extern struct taginfo *cgit_parse_tag(struct tag *tag); 230extern struct taginfo *cgit_parse_tag(struct tag *tag);
223extern void cgit_parse_url(const char *url); 231extern void cgit_parse_url(const char *url);
224 232
225extern char *cache_safe_filename(const char *unsafe); 233extern char *cache_safe_filename(const char *unsafe);
226extern int cache_lock(struct cacheitem *item); 234extern int cache_lock(struct cacheitem *item);
227extern int cache_unlock(struct cacheitem *item); 235extern int cache_unlock(struct cacheitem *item);
228extern int cache_cancel_lock(struct cacheitem *item); 236extern int cache_cancel_lock(struct cacheitem *item);
229extern int cache_exist(struct cacheitem *item); 237extern int cache_exist(struct cacheitem *item);
230extern int cache_expired(struct cacheitem *item); 238extern int cache_expired(struct cacheitem *item);
231 239
232extern char *cgit_repourl(const char *reponame); 240extern char *cgit_repourl(const char *reponame);
233extern char *cgit_fileurl(const char *reponame, const char *pagename, 241extern char *cgit_fileurl(const char *reponame, const char *pagename,
234 const char *filename, const char *query); 242 const char *filename, const char *query);
235extern char *cgit_pageurl(const char *reponame, const char *pagename, 243extern char *cgit_pageurl(const char *reponame, const char *pagename,
236 const char *query); 244 const char *query);
237 245
238extern const char *cgit_repobasename(const char *reponame); 246extern const char *cgit_repobasename(const char *reponame);
239 247
240extern void cgit_tree_link(char *name, char *title, char *class, char *head, 248extern void cgit_tree_link(char *name, char *title, char *class, char *head,
241 char *rev, char *path); 249 char *rev, char *path);
242extern void cgit_log_link(char *name, char *title, char *class, char *head, 250extern void cgit_log_link(char *name, char *title, char *class, char *head,
243 char *rev, char *path, int ofs, char *grep, 251 char *rev, char *path, int ofs, char *grep,
244 char *pattern); 252 char *pattern);
245extern void cgit_commit_link(char *name, char *title, char *class, char *head, 253extern void cgit_commit_link(char *name, char *title, char *class, char *head,
246 char *rev); 254 char *rev);
247extern void cgit_refs_link(char *name, char *title, char *class, char *head, 255extern void cgit_refs_link(char *name, char *title, char *class, char *head,
248 char *rev, char *path); 256 char *rev, char *path);
249extern void cgit_snapshot_link(char *name, char *title, char *class, 257extern void cgit_snapshot_link(char *name, char *title, char *class,
250 char *head, char *rev, char *archivename); 258 char *head, char *rev, char *archivename);
251extern void cgit_diff_link(char *name, char *title, char *class, char *head, 259extern void cgit_diff_link(char *name, char *title, char *class, char *head,
252 char *new_rev, char *old_rev, char *path); 260 char *new_rev, char *old_rev, char *path);
253 261
254extern void cgit_object_link(struct object *obj); 262extern void cgit_object_link(struct object *obj);
255 263
256extern void cgit_print_error(char *msg); 264extern void cgit_print_error(char *msg);
257extern void cgit_print_date(time_t secs, char *format); 265extern void cgit_print_date(time_t secs, char *format);
258extern void cgit_print_age(time_t t, time_t max_relative, char *format); 266extern void cgit_print_age(time_t t, time_t max_relative, char *format);
259extern void cgit_print_http_headers(struct cgit_context *ctx); 267extern void cgit_print_http_headers(struct cgit_context *ctx);
260extern void cgit_print_docstart(struct cgit_context *ctx); 268extern void cgit_print_docstart(struct cgit_context *ctx);
261extern void cgit_print_docend(); 269extern void cgit_print_docend();
262extern void cgit_print_pageheader(struct cgit_context *ctx); 270extern void cgit_print_pageheader(struct cgit_context *ctx);
263extern void cgit_print_filemode(unsigned short mode); 271extern void cgit_print_filemode(unsigned short mode);
264extern void cgit_print_branches(int maxcount); 272extern void cgit_print_branches(int maxcount);
265extern void cgit_print_tags(int maxcount); 273extern void cgit_print_tags(int maxcount);
266 274
267extern void cgit_print_repolist(); 275extern void cgit_print_repolist();
268extern void cgit_print_summary(); 276extern void cgit_print_summary();
269extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, 277extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep,
270 char *pattern, char *path, int pager); 278 char *pattern, char *path, int pager);
271extern void cgit_print_blob(const char *hex, char *path); 279extern void cgit_print_blob(const char *hex, char *path);
272extern void cgit_print_tree(const char *rev, char *path); 280extern void cgit_print_tree(const char *rev, char *path);
273extern void cgit_print_commit(char *hex); 281extern void cgit_print_commit(char *hex);
274extern void cgit_print_refs(); 282extern void cgit_print_refs();
275extern void cgit_print_tag(char *revname); 283extern void cgit_print_tag(char *revname);
276extern void cgit_print_diff(const char *new_hex, const char *old_hex, const char *prefix); 284extern void cgit_print_diff(const char *new_hex, const char *old_hex, const char *prefix);
277extern void cgit_print_patch(char *hex); 285extern void cgit_print_patch(char *hex);
278extern void cgit_print_snapshot(const char *head, const char *hex, 286extern void cgit_print_snapshot(const char *head, const char *hex,
279 const char *prefix, const char *filename, 287 const char *prefix, const char *filename,
diff --git a/shared.c b/shared.c
index 67eb67b..800c06a 100644
--- a/shared.c
+++ b/shared.c
@@ -386,96 +386,123 @@ int buflen = 0;
386 386
387int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf) 387int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)
388{ 388{
389 int i; 389 int i;
390 390
391 for (i = 0; i < nbuf; i++) { 391 for (i = 0; i < nbuf; i++) {
392 if (mb[i].ptr[mb[i].size-1] != '\n') { 392 if (mb[i].ptr[mb[i].size-1] != '\n') {
393 /* Incomplete line */ 393 /* Incomplete line */
394 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 394 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
395 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 395 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
396 buflen += mb[i].size; 396 buflen += mb[i].size;
397 continue; 397 continue;
398 } 398 }
399 399
400 /* we have a complete line */ 400 /* we have a complete line */
401 if (!diffbuf) { 401 if (!diffbuf) {
402 ((linediff_fn)priv)(mb[i].ptr, mb[i].size); 402 ((linediff_fn)priv)(mb[i].ptr, mb[i].size);
403 continue; 403 continue;
404 } 404 }
405 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 405 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
406 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 406 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
407 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size); 407 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size);
408 free(diffbuf); 408 free(diffbuf);
409 diffbuf = NULL; 409 diffbuf = NULL;
410 buflen = 0; 410 buflen = 0;
411 } 411 }
412 if (diffbuf) { 412 if (diffbuf) {
413 ((linediff_fn)priv)(diffbuf, buflen); 413 ((linediff_fn)priv)(diffbuf, buflen);
414 free(diffbuf); 414 free(diffbuf);
415 diffbuf = NULL; 415 diffbuf = NULL;
416 buflen = 0; 416 buflen = 0;
417 } 417 }
418 return 0; 418 return 0;
419} 419}
420 420
421int cgit_diff_files(const unsigned char *old_sha1, 421int cgit_diff_files(const unsigned char *old_sha1,
422 const unsigned char *new_sha1, 422 const unsigned char *new_sha1,
423 linediff_fn fn) 423 linediff_fn fn)
424{ 424{
425 mmfile_t file1, file2; 425 mmfile_t file1, file2;
426 xpparam_t diff_params; 426 xpparam_t diff_params;
427 xdemitconf_t emit_params; 427 xdemitconf_t emit_params;
428 xdemitcb_t emit_cb; 428 xdemitcb_t emit_cb;
429 429
430 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1)) 430 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1))
431 return 1; 431 return 1;
432 432
433 diff_params.flags = XDF_NEED_MINIMAL; 433 diff_params.flags = XDF_NEED_MINIMAL;
434 emit_params.ctxlen = 3; 434 emit_params.ctxlen = 3;
435 emit_params.flags = XDL_EMIT_FUNCNAMES; 435 emit_params.flags = XDL_EMIT_FUNCNAMES;
436 emit_params.find_func = NULL; 436 emit_params.find_func = NULL;
437 emit_cb.outf = filediff_cb; 437 emit_cb.outf = filediff_cb;
438 emit_cb.priv = fn; 438 emit_cb.priv = fn;
439 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); 439 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb);
440 return 0; 440 return 0;
441} 441}
442 442
443void cgit_diff_tree(const unsigned char *old_sha1, 443void cgit_diff_tree(const unsigned char *old_sha1,
444 const unsigned char *new_sha1, 444 const unsigned char *new_sha1,
445 filepair_fn fn, const char *prefix) 445 filepair_fn fn, const char *prefix)
446{ 446{
447 struct diff_options opt; 447 struct diff_options opt;
448 int ret; 448 int ret;
449 int prefixlen; 449 int prefixlen;
450 450
451 diff_setup(&opt); 451 diff_setup(&opt);
452 opt.output_format = DIFF_FORMAT_CALLBACK; 452 opt.output_format = DIFF_FORMAT_CALLBACK;
453 opt.detect_rename = 1; 453 opt.detect_rename = 1;
454 opt.rename_limit = ctx.cfg.renamelimit; 454 opt.rename_limit = ctx.cfg.renamelimit;
455 DIFF_OPT_SET(&opt, RECURSIVE); 455 DIFF_OPT_SET(&opt, RECURSIVE);
456 opt.format_callback = cgit_diff_tree_cb; 456 opt.format_callback = cgit_diff_tree_cb;
457 opt.format_callback_data = fn; 457 opt.format_callback_data = fn;
458 if (prefix) { 458 if (prefix) {
459 opt.nr_paths = 1; 459 opt.nr_paths = 1;
460 opt.paths = &prefix; 460 opt.paths = &prefix;
461 prefixlen = strlen(prefix); 461 prefixlen = strlen(prefix);
462 opt.pathlens = &prefixlen; 462 opt.pathlens = &prefixlen;
463 } 463 }
464 diff_setup_done(&opt); 464 diff_setup_done(&opt);
465 465
466 if (old_sha1 && !is_null_sha1(old_sha1)) 466 if (old_sha1 && !is_null_sha1(old_sha1))
467 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt); 467 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt);
468 else 468 else
469 ret = diff_root_tree_sha1(new_sha1, "", &opt); 469 ret = diff_root_tree_sha1(new_sha1, "", &opt);
470 diffcore_std(&opt); 470 diffcore_std(&opt);
471 diff_flush(&opt); 471 diff_flush(&opt);
472} 472}
473 473
474void cgit_diff_commit(struct commit *commit, filepair_fn fn) 474void cgit_diff_commit(struct commit *commit, filepair_fn fn)
475{ 475{
476 unsigned char *old_sha1 = NULL; 476 unsigned char *old_sha1 = NULL;
477 477
478 if (commit->parents) 478 if (commit->parents)
479 old_sha1 = commit->parents->item->object.sha1; 479 old_sha1 = commit->parents->item->object.sha1;
480 cgit_diff_tree(old_sha1, commit->object.sha1, fn, NULL); 480 cgit_diff_tree(old_sha1, commit->object.sha1, fn, NULL);
481} 481}
482
483int cgit_parse_snapshots_mask(const char *str)
484{
485 const struct cgit_snapshot_format *f;
486 static const char *delim = " \t,:/|;";
487 int tl, sl, rv = 0;
488
489 /* favor legacy setting */
490 if(atoi(str))
491 return 1;
492 for(;;) {
493 str += strspn(str,delim);
494 tl = strcspn(str,delim);
495 if (!tl)
496 break;
497 for (f = cgit_snapshot_formats; f->suffix; f++) {
498 sl = strlen(f->suffix);
499 if((tl == sl && !strncmp(f->suffix, str, tl)) ||
500 (tl == sl-1 && !strncmp(f->suffix+1, str, tl-1))) {
501 rv |= f->bit;
502 break;
503 }
504 }
505 str += tl;
506 }
507 return rv;
508}
diff --git a/ui-shared.c b/ui-shared.c
index 2596023..aa65988 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -480,97 +480,112 @@ void cgit_print_pageheader(struct cgit_context *ctx)
480 ctx->cfg.logo); 480 ctx->cfg.logo);
481 html("</td></tr>\n<tr><td class='sidebar'>\n"); 481 html("</td></tr>\n<tr><td class='sidebar'>\n");
482 if (ctx->repo) { 482 if (ctx->repo) {
483 html("<h1 class='first'>"); 483 html("<h1 class='first'>");
484 html_txt(strrpart(ctx->repo->name, 20)); 484 html_txt(strrpart(ctx->repo->name, 20));
485 html("</h1>\n"); 485 html("</h1>\n");
486 html_txt(ctx->repo->desc); 486 html_txt(ctx->repo->desc);
487 if (ctx->repo->owner) { 487 if (ctx->repo->owner) {
488 html("<h1>owner</h1>\n"); 488 html("<h1>owner</h1>\n");
489 html_txt(ctx->repo->owner); 489 html_txt(ctx->repo->owner);
490 } 490 }
491 html("<h1>navigate</h1>\n"); 491 html("<h1>navigate</h1>\n");
492 reporevlink(NULL, "summary", NULL, "menu", ctx->qry.head, 492 reporevlink(NULL, "summary", NULL, "menu", ctx->qry.head,
493 NULL, NULL); 493 NULL, NULL);
494 cgit_log_link("log", NULL, "menu", ctx->qry.head, NULL, NULL, 494 cgit_log_link("log", NULL, "menu", ctx->qry.head, NULL, NULL,
495 0, NULL, NULL); 495 0, NULL, NULL);
496 cgit_tree_link("tree", NULL, "menu", ctx->qry.head, 496 cgit_tree_link("tree", NULL, "menu", ctx->qry.head,
497 ctx->qry.sha1, NULL); 497 ctx->qry.sha1, NULL);
498 cgit_commit_link("commit", NULL, "menu", ctx->qry.head, 498 cgit_commit_link("commit", NULL, "menu", ctx->qry.head,
499 ctx->qry.sha1); 499 ctx->qry.sha1);
500 cgit_diff_link("diff", NULL, "menu", ctx->qry.head, 500 cgit_diff_link("diff", NULL, "menu", ctx->qry.head,
501 ctx->qry.sha1, ctx->qry.sha2, NULL); 501 ctx->qry.sha1, ctx->qry.sha2, NULL);
502 cgit_patch_link("patch", NULL, "menu", ctx->qry.head, 502 cgit_patch_link("patch", NULL, "menu", ctx->qry.head,
503 ctx->qry.sha1); 503 ctx->qry.sha1);
504 504
505 for_each_ref(print_archive_ref, &header); 505 for_each_ref(print_archive_ref, &header);
506 506
507 if (ctx->repo->clone_url || ctx->cfg.clone_prefix) { 507 if (ctx->repo->clone_url || ctx->cfg.clone_prefix) {
508 html("<h1>clone</h1>\n"); 508 html("<h1>clone</h1>\n");
509 if (ctx->repo->clone_url) 509 if (ctx->repo->clone_url)
510 url = ctx->repo->clone_url; 510 url = ctx->repo->clone_url;
511 else 511 else
512 url = fmt("%s%s", ctx->cfg.clone_prefix, 512 url = fmt("%s%s", ctx->cfg.clone_prefix,
513 ctx->repo->url); 513 ctx->repo->url);
514 html("<a class='menu' href='"); 514 html("<a class='menu' href='");
515 html_attr(url); 515 html_attr(url);
516 html("' title='"); 516 html("' title='");
517 html_attr(url); 517 html_attr(url);
518 html("'>\n"); 518 html("'>\n");
519 html_txt(strrpart(url, 20)); 519 html_txt(strrpart(url, 20));
520 html("</a>\n"); 520 html("</a>\n");
521 } 521 }
522 522
523 html("<h1>branch</h1>\n"); 523 html("<h1>branch</h1>\n");
524 html("<form method='get' action=''>\n"); 524 html("<form method='get' action=''>\n");
525 add_hidden_formfields(0, 1, ctx->qry.page); 525 add_hidden_formfields(0, 1, ctx->qry.page);
526 // html("<table summary='branch selector' class='grid'><tr><td id='branch-dropdown-cell'>"); 526 // html("<table summary='branch selector' class='grid'><tr><td id='branch-dropdown-cell'>");
527 html("<select name='h' onchange='this.form.submit();'>\n"); 527 html("<select name='h' onchange='this.form.submit();'>\n");
528 for_each_branch_ref(print_branch_option, ctx->qry.head); 528 for_each_branch_ref(print_branch_option, ctx->qry.head);
529 html("</select>\n"); 529 html("</select>\n");
530 // html("</td><td>"); 530 // html("</td><td>");
531 html("<noscript><input type='submit' id='switch-btn' value='switch'/></noscript>\n"); 531 html("<noscript><input type='submit' id='switch-btn' value='switch'/></noscript>\n");
532 // html("</td></tr></table>"); 532 // html("</td></tr></table>");
533 html("</form>\n"); 533 html("</form>\n");
534 534
535 html("<h1>search</h1>\n"); 535 html("<h1>search</h1>\n");
536 html("<form method='get' action='"); 536 html("<form method='get' action='");
537 if (ctx->cfg.virtual_root) 537 if (ctx->cfg.virtual_root)
538 html_attr(cgit_fileurl(ctx->qry.repo, "log", 538 html_attr(cgit_fileurl(ctx->qry.repo, "log",
539 ctx->qry.path, NULL)); 539 ctx->qry.path, NULL));
540 html("'>\n"); 540 html("'>\n");
541 add_hidden_formfields(1, 0, "log"); 541 add_hidden_formfields(1, 0, "log");
542 html("<select name='qt'>\n"); 542 html("<select name='qt'>\n");
543 html_option("grep", "log msg", ctx->qry.grep); 543 html_option("grep", "log msg", ctx->qry.grep);
544 html_option("author", "author", ctx->qry.grep); 544 html_option("author", "author", ctx->qry.grep);
545 html_option("committer", "committer", ctx->qry.grep); 545 html_option("committer", "committer", ctx->qry.grep);
546 html("</select>\n"); 546 html("</select>\n");
547 html("<input class='txt' type='text' name='q' value='"); 547 html("<input class='txt' type='text' name='q' value='");
548 html_attr(ctx->qry.search); 548 html_attr(ctx->qry.search);
549 html("'/>\n"); 549 html("'/>\n");
550 html("</form>\n"); 550 html("</form>\n");
551 } else { 551 } else {
552 if (!ctx->cfg.index_info || html_include(ctx->cfg.index_info)) 552 if (!ctx->cfg.index_info || html_include(ctx->cfg.index_info))
553 html(default_info); 553 html(default_info);
554 } 554 }
555 555
556 html("</td></tr></table></td>\n"); 556 html("</td></tr></table></td>\n");
557 557
558 html("<td id='content'>\n"); 558 html("<td id='content'>\n");
559} 559}
560 560
561void cgit_print_filemode(unsigned short mode) 561void cgit_print_filemode(unsigned short mode)
562{ 562{
563 if (S_ISDIR(mode)) 563 if (S_ISDIR(mode))
564 html("d"); 564 html("d");
565 else if (S_ISLNK(mode)) 565 else if (S_ISLNK(mode))
566 html("l"); 566 html("l");
567 else if (S_ISGITLINK(mode)) 567 else if (S_ISGITLINK(mode))
568 html("m"); 568 html("m");
569 else 569 else
570 html("-"); 570 html("-");
571 html_fileperm(mode >> 6); 571 html_fileperm(mode >> 6);
572 html_fileperm(mode >> 3); 572 html_fileperm(mode >> 3);
573 html_fileperm(mode); 573 html_fileperm(mode);
574} 574}
575 575
576/* vim:set sw=8: */ 576void cgit_print_snapshot_links(const char *repo, const char *head,
577 const char *hex, int snapshots)
578{
579 const struct cgit_snapshot_format* f;
580 char *filename;
581
582 for (f = cgit_snapshot_formats; f->suffix; f++) {
583 if (!(snapshots & f->bit))
584 continue;
585 filename = fmt("%s-%s%s", cgit_repobasename(repo), hex,
586 f->suffix);
587 cgit_snapshot_link(filename, NULL, NULL, (char *)head,
588 (char *)hex, filename);
589 html("<br/>");
590 }
591}
diff --git a/ui-snapshot.c b/ui-snapshot.c
index c741469..512fcd2 100644
--- a/ui-snapshot.c
+++ b/ui-snapshot.c
@@ -1,159 +1,113 @@
1/* ui-snapshot.c: generate snapshot of a commit 1/* ui-snapshot.c: generate snapshot of a commit
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 11
12static int write_compressed_tar_archive(struct archiver_args *args,const char *filter) 12static int write_compressed_tar_archive(struct archiver_args *args,const char *filter)
13{ 13{
14 int rw[2]; 14 int rw[2];
15 pid_t gzpid; 15 pid_t gzpid;
16 int stdout2; 16 int stdout2;
17 int status; 17 int status;
18 int rv; 18 int rv;
19 19
20 stdout2 = chk_non_negative(dup(STDIN_FILENO), "Preserving STDOUT before compressing"); 20 stdout2 = chk_non_negative(dup(STDIN_FILENO), "Preserving STDOUT before compressing");
21 chk_zero(pipe(rw), "Opening pipe from compressor subprocess"); 21 chk_zero(pipe(rw), "Opening pipe from compressor subprocess");
22 gzpid = chk_non_negative(fork(), "Forking compressor subprocess"); 22 gzpid = chk_non_negative(fork(), "Forking compressor subprocess");
23 if(gzpid==0) { 23 if(gzpid==0) {
24 /* child */ 24 /* child */
25 chk_zero(close(rw[1]), "Closing write end of pipe in child"); 25 chk_zero(close(rw[1]), "Closing write end of pipe in child");
26 chk_zero(close(STDIN_FILENO), "Closing STDIN"); 26 chk_zero(close(STDIN_FILENO), "Closing STDIN");
27 chk_non_negative(dup2(rw[0],STDIN_FILENO), "Redirecting compressor input to stdin"); 27 chk_non_negative(dup2(rw[0],STDIN_FILENO), "Redirecting compressor input to stdin");
28 execlp(filter,filter,NULL); 28 execlp(filter,filter,NULL);
29 _exit(-1); 29 _exit(-1);
30 } 30 }
31 /* parent */ 31 /* parent */
32 chk_zero(close(rw[0]), "Closing read end of pipe"); 32 chk_zero(close(rw[0]), "Closing read end of pipe");
33 chk_non_negative(dup2(rw[1],STDOUT_FILENO), "Redirecting output to compressor"); 33 chk_non_negative(dup2(rw[1],STDOUT_FILENO), "Redirecting output to compressor");
34 34
35 rv = write_tar_archive(args); 35 rv = write_tar_archive(args);
36 36
37 chk_zero(close(STDOUT_FILENO), "Closing STDOUT redirected to compressor"); 37 chk_zero(close(STDOUT_FILENO), "Closing STDOUT redirected to compressor");
38 chk_non_negative(dup2(stdout2,STDOUT_FILENO), "Restoring uncompressed STDOUT"); 38 chk_non_negative(dup2(stdout2,STDOUT_FILENO), "Restoring uncompressed STDOUT");
39 chk_zero(close(stdout2), "Closing uncompressed STDOUT"); 39 chk_zero(close(stdout2), "Closing uncompressed STDOUT");
40 chk_zero(close(rw[1]), "Closing write end of pipe in parent"); 40 chk_zero(close(rw[1]), "Closing write end of pipe in parent");
41 chk_positive(waitpid(gzpid,&status,0), "Waiting on compressor process"); 41 chk_positive(waitpid(gzpid,&status,0), "Waiting on compressor process");
42 if(! ( WIFEXITED(status) && WEXITSTATUS(status)==0 ) ) 42 if(! ( WIFEXITED(status) && WEXITSTATUS(status)==0 ) )
43 cgit_print_error("Failed to compress archive"); 43 cgit_print_error("Failed to compress archive");
44 44
45 return rv; 45 return rv;
46} 46}
47 47
48static int write_tar_gzip_archive(struct archiver_args *args) 48static int write_tar_gzip_archive(struct archiver_args *args)
49{ 49{
50 return write_compressed_tar_archive(args,"gzip"); 50 return write_compressed_tar_archive(args,"gzip");
51} 51}
52 52
53static int write_tar_bzip2_archive(struct archiver_args *args) 53static int write_tar_bzip2_archive(struct archiver_args *args)
54{ 54{
55 return write_compressed_tar_archive(args,"bzip2"); 55 return write_compressed_tar_archive(args,"bzip2");
56} 56}
57 57
58static const struct snapshot_archive_t { 58const struct cgit_snapshot_format cgit_snapshot_formats[] = {
59 const char *suffix;
60 const char *mimetype;
61 write_archive_fn_t write_func;
62 int bit;
63 }snapshot_archives[] = {
64 { ".zip", "application/x-zip", write_zip_archive, 0x1 }, 59 { ".zip", "application/x-zip", write_zip_archive, 0x1 },
65 { ".tar.gz", "application/x-tar", write_tar_gzip_archive, 0x2 }, 60 { ".tar.gz", "application/x-tar", write_tar_gzip_archive, 0x2 },
66 { ".tar.bz2", "application/x-tar", write_tar_bzip2_archive, 0x4 }, 61 { ".tar.bz2", "application/x-tar", write_tar_bzip2_archive, 0x4 },
67 { ".tar", "application/x-tar", write_tar_archive, 0x8 } 62 { ".tar", "application/x-tar", write_tar_archive, 0x8 },
63 {}
68}; 64};
69 65
70#define snapshot_archives_len (sizeof(snapshot_archives) / sizeof(*snapshot_archives)) 66static int make_snapshot(const struct cgit_snapshot_format *format,
71 67 const char *hex, const char *prefix,
72void cgit_print_snapshot(const char *head, const char *hex, const char *prefix, 68 const char *filename)
73 const char *filename, int snapshots)
74{ 69{
75 const struct snapshot_archive_t* sat;
76 struct archiver_args args; 70 struct archiver_args args;
77 struct commit *commit; 71 struct commit *commit;
78 unsigned char sha1[20]; 72 unsigned char sha1[20];
79 int f, sl, fnl = strlen(filename);
80 73
81 for(f=0; f<snapshot_archives_len; f++) { 74 if(get_sha1(hex, sha1)) {
82 sat = &snapshot_archives[f]; 75 cgit_print_error(fmt("Bad object id: %s", hex));
83 if(!(snapshots & sat->bit)) 76 return 1;
84 continue;
85 sl = strlen(sat->suffix);
86 if(fnl<sl || strcmp(&filename[fnl-sl],sat->suffix))
87 continue;
88 if (!hex)
89 hex = head;
90 if(get_sha1(hex, sha1)) {
91 cgit_print_error(fmt("Bad object id: %s", hex));
92 return;
93 }
94 commit = lookup_commit_reference(sha1);
95 if(!commit) {
96 cgit_print_error(fmt("Not a commit reference: %s", hex));
97 return;;
98 }
99 memset(&args,0,sizeof(args));
100 args.base = fmt("%s/", prefix);
101 args.tree = commit->tree;
102 args.time = commit->date;
103 ctx.page.mimetype = xstrdup(sat->mimetype);
104 ctx.page.filename = xstrdup(filename);
105 cgit_print_http_headers(&ctx);
106 (*sat->write_func)(&args);
107 return;
108 } 77 }
109 cgit_print_error(fmt("Unsupported snapshot format: %s", filename)); 78 commit = lookup_commit_reference(sha1);
110} 79 if(!commit) {
111 80 cgit_print_error(fmt("Not a commit reference: %s", hex));
112void cgit_print_snapshot_links(const char *repo, const char *head, 81 return 1;
113 const char *hex, int snapshots)
114{
115 const struct snapshot_archive_t* sat;
116 char *filename;
117 int f;
118
119 for(f=0; f<snapshot_archives_len; f++) {
120 sat = &snapshot_archives[f];
121 if(!(snapshots & sat->bit))
122 continue;
123 filename = fmt("%s-%s%s", cgit_repobasename(repo), hex,
124 sat->suffix);
125 cgit_snapshot_link(filename, NULL, NULL, (char *)head,
126 (char *)hex, filename);
127 html("<br/>");
128 } 82 }
83 memset(&args, 0, sizeof(args));
84 args.base = fmt("%s/", prefix);
85 args.tree = commit->tree;
86 args.time = commit->date;
87 ctx.page.mimetype = xstrdup(format->mimetype);
88 ctx.page.filename = xstrdup(filename);
89 cgit_print_http_headers(&ctx);
90 format->write_func(&args);
91 return 0;
129} 92}
130 93
131int cgit_parse_snapshots_mask(const char *str) 94void cgit_print_snapshot(const char *head, const char *hex, const char *prefix,
95 const char *filename, int snapshots)
132{ 96{
133 const struct snapshot_archive_t* sat; 97 const struct cgit_snapshot_format* f;
134 static const char *delim = " \t,:/|;"; 98 int sl, fnl;
135 int f, tl, sl, rv = 0; 99
136 100 fnl = strlen(filename);
137 /* favor legacy setting */ 101 if (!hex)
138 if(atoi(str)) 102 hex = head;
139 return 1; 103 for (f = cgit_snapshot_formats; f->suffix; f++) {
140 for(;;) { 104 if (!(snapshots & f->bit))
141 str += strspn(str,delim); 105 continue;
142 tl = strcspn(str,delim); 106 sl = strlen(f->suffix);
143 if(!tl) 107 if(fnl < sl || strcmp(&filename[fnl-sl], f->suffix))
144 break; 108 continue;
145 for(f=0; f<snapshot_archives_len; f++) { 109 make_snapshot(f, hex, prefix, filename);
146 sat = &snapshot_archives[f]; 110 return;
147 sl = strlen(sat->suffix);
148 if((tl == sl && !strncmp(sat->suffix, str, tl)) ||
149 (tl == sl-1 && !strncmp(sat->suffix+1, str, tl-1))) {
150 rv |= sat->bit;
151 break;
152 }
153 }
154 str += tl;
155 } 111 }
156 return rv; 112 cgit_print_error(fmt("Unsupported snapshot format: %s", filename));
157} 113}
158
159/* vim:set sw=8: */