summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c6
-rw-r--r--cgit.css1
-rw-r--r--cgit.h11
-rw-r--r--cgitrc5
-rw-r--r--shared.c11
-rw-r--r--ui-commit.c9
-rw-r--r--ui-shared.c41
-rw-r--r--ui-snapshot.c150
-rw-r--r--ui-tree.c4
9 files changed, 194 insertions, 44 deletions
diff --git a/cgit.c b/cgit.c
index 4b91829..6597529 100644
--- a/cgit.c
+++ b/cgit.c
@@ -65,14 +65,16 @@ static void cgit_print_repo_page(struct cacheitem *item)
65 65
66 title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc); 66 title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc);
67 show_search = 0; 67 show_search = 0;
68 setenv("GIT_DIR", cgit_repo->path, 1); 68 setenv("GIT_DIR", cgit_repo->path, 1);
69 69
70 if ((cgit_cmd == CMD_SNAPSHOT) && cgit_repo->snapshots) { 70 if ((cgit_cmd == CMD_SNAPSHOT) && cgit_repo->snapshots) {
71 cgit_print_snapshot(item, cgit_query_sha1, "zip", 71 cgit_print_snapshot(item, cgit_query_sha1,
72 cgit_repo->url, cgit_query_name); 72 cgit_repobasename(cgit_repo->url),
73 cgit_query_name,
74 cgit_repo->snapshots );
73 return; 75 return;
74 } 76 }
75 77
76 if (cgit_cmd == CMD_BLOB) { 78 if (cgit_cmd == CMD_BLOB) {
77 cgit_print_blob(item, cgit_query_sha1, cgit_query_path); 79 cgit_print_blob(item, cgit_query_sha1, cgit_query_path);
78 return; 80 return;
diff --git a/cgit.css b/cgit.css
index 112dac1..43a40a3 100644
--- a/cgit.css
+++ b/cgit.css
@@ -228,12 +228,13 @@ table.commit-info {
228} 228}
229 229
230table.commit-info th { 230table.commit-info th {
231 text-align: left; 231 text-align: left;
232 font-weight: normal; 232 font-weight: normal;
233 padding: 0.1em 1em 0.1em 0.1em; 233 padding: 0.1em 1em 0.1em 0.1em;
234 vertical-align: top;
234} 235}
235 236
236table.commit-info td { 237table.commit-info td {
237 font-weight: normal; 238 font-weight: normal;
238 padding: 0.1em 1em 0.1em 0.1em; 239 padding: 0.1em 1em 0.1em 0.1em;
239} 240}
diff --git a/cgit.h b/cgit.h
index 610a16d..eddcaa3 100644
--- a/cgit.h
+++ b/cgit.h
@@ -154,12 +154,13 @@ extern struct repoinfo *cgit_get_repoinfo(const char *url);
154extern void cgit_global_config_cb(const char *name, const char *value); 154extern void cgit_global_config_cb(const char *name, const char *value);
155extern void cgit_repo_config_cb(const char *name, const char *value); 155extern void cgit_repo_config_cb(const char *name, const char *value);
156extern void cgit_querystring_cb(const char *name, const char *value); 156extern void cgit_querystring_cb(const char *name, const char *value);
157 157
158extern int chk_zero(int result, char *msg); 158extern int chk_zero(int result, char *msg);
159extern int chk_positive(int result, char *msg); 159extern int chk_positive(int result, char *msg);
160extern int chk_non_negative(int result, char *msg);
160 161
161extern int hextoint(char c); 162extern int hextoint(char c);
162extern char *trim_end(const char *str, char c); 163extern char *trim_end(const char *str, char c);
163 164
164extern void *cgit_free_commitinfo(struct commitinfo *info); 165extern void *cgit_free_commitinfo(struct commitinfo *info);
165 166
@@ -197,15 +198,19 @@ extern int cache_lock(struct cacheitem *item);
197extern int cache_unlock(struct cacheitem *item); 198extern int cache_unlock(struct cacheitem *item);
198extern int cache_cancel_lock(struct cacheitem *item); 199extern int cache_cancel_lock(struct cacheitem *item);
199extern int cache_exist(struct cacheitem *item); 200extern int cache_exist(struct cacheitem *item);
200extern int cache_expired(struct cacheitem *item); 201extern int cache_expired(struct cacheitem *item);
201 202
202extern char *cgit_repourl(const char *reponame); 203extern char *cgit_repourl(const char *reponame);
204extern char *cgit_fileurl(const char *reponame, const char *pagename,
205 const char *filename, const char *query);
203extern char *cgit_pageurl(const char *reponame, const char *pagename, 206extern char *cgit_pageurl(const char *reponame, const char *pagename,
204 const char *query); 207 const char *query);
205 208
209extern const char *cgit_repobasename(const char *reponame);
210
206extern void cgit_tree_link(char *name, char *title, char *class, char *head, 211extern void cgit_tree_link(char *name, char *title, char *class, char *head,
207 char *rev, char *path); 212 char *rev, char *path);
208extern void cgit_log_link(char *name, char *title, char *class, char *head, 213extern void cgit_log_link(char *name, char *title, char *class, char *head,
209 char *rev, char *path, int ofs); 214 char *rev, char *path, int ofs);
210extern void cgit_commit_link(char *name, char *title, char *class, char *head, 215extern void cgit_commit_link(char *name, char *title, char *class, char *head,
211 char *rev); 216 char *rev);
@@ -230,10 +235,12 @@ extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *
230extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); 235extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path);
231extern void cgit_print_tree(const char *rev, char *path); 236extern void cgit_print_tree(const char *rev, char *path);
232extern void cgit_print_commit(char *hex); 237extern void cgit_print_commit(char *hex);
233extern void cgit_print_tag(char *revname); 238extern void cgit_print_tag(char *revname);
234extern void cgit_print_diff(const char *new_hex, const char *old_hex); 239extern void cgit_print_diff(const char *new_hex, const char *old_hex);
235extern void cgit_print_snapshot(struct cacheitem *item, const char *hex, 240extern void cgit_print_snapshot(struct cacheitem *item, const char *hex,
236 const char *format, const char *prefix, 241 const char *prefix, const char *filename,
237 const char *filename); 242 int snapshot);
243extern void cgit_print_snapshot_links(const char *repo, const char *hex,int snapshots);
244extern int cgit_parse_snapshots_mask(const char *str);
238 245
239#endif /* CGIT_H */ 246#endif /* CGIT_H */
diff --git a/cgitrc b/cgitrc
index 40877f8..1040997 100644
--- a/cgitrc
+++ b/cgitrc
@@ -5,13 +5,14 @@
5 5
6## Uncomment and set to 1 to deactivate caching of generated pages. Mostly 6## Uncomment and set to 1 to deactivate caching of generated pages. Mostly
7## usefull for testing. 7## usefull for testing.
8#nocache=0 8#nocache=0
9 9
10 10
11## Enable/disable snapshots by default. This can be overridden per repo 11## Set allowed snapshot types by default. Can be overridden per repo
12# can be any combination of zip/tar.gz/tar.bz2/tar
12#snapshots=0 13#snapshots=0
13 14
14 15
15## Enable/disable extra links to summary/log/tree per repo on index page 16## Enable/disable extra links to summary/log/tree per repo on index page
16#enable-index-links=0 17#enable-index-links=0
17 18
@@ -110,11 +111,11 @@
110## repository section must start with repo.url). 111## repository section must start with repo.url).
111#repo.url=cgit 112#repo.url=cgit
112#repo.name=cgit 113#repo.name=cgit
113#repo.desc=the caching cgi for git 114#repo.desc=the caching cgi for git
114#repo.path=/pub/git/cgit 115#repo.path=/pub/git/cgit
115#repo.owner=Lars Hjemli 116#repo.owner=Lars Hjemli
116 #repo.snapshots=1 # override a sitewide snapshot-setting 117 #repo.snapshots=tar.bz2 # override a sitewide snapshot-setting
117 #repo.enable-log-filecount=0 # override the default filecount setting 118 #repo.enable-log-filecount=0 # override the default filecount setting
118 #repo.enable-log-linecount=0 # override the default linecount setting 119 #repo.enable-log-linecount=0 # override the default linecount setting
119 #repo.module-link=/git/%s/commit/?id=%s # override the standard module-link 120 #repo.module-link=/git/%s/commit/?id=%s # override the standard module-link
120 #repo.readme=info/web/readme # specify a file to include on summary page 121 #repo.readme=info/web/readme # specify a file to include on summary page
diff --git a/shared.c b/shared.c
index 06693b0..077934f 100644
--- a/shared.c
+++ b/shared.c
@@ -83,12 +83,19 @@ int chk_positive(int result, char *msg)
83{ 83{
84 if (result <= 0) 84 if (result <= 0)
85 die("%s: %s", msg, strerror(errno)); 85 die("%s: %s", msg, strerror(errno));
86 return result; 86 return result;
87} 87}
88 88
89int chk_non_negative(int result, char *msg)
90{
91 if (result < 0)
92 die("%s: %s",msg, strerror(errno));
93 return result;
94}
95
89struct repoinfo *add_repo(const char *url) 96struct repoinfo *add_repo(const char *url)
90{ 97{
91 struct repoinfo *ret; 98 struct repoinfo *ret;
92 99
93 if (++cgit_repolist.count > cgit_repolist.length) { 100 if (++cgit_repolist.count > cgit_repolist.length) {
94 if (cgit_repolist.length == 0) 101 if (cgit_repolist.length == 0)
@@ -145,13 +152,13 @@ void cgit_global_config_cb(const char *name, const char *value)
145 cgit_module_link = xstrdup(value); 152 cgit_module_link = xstrdup(value);
146 else if (!strcmp(name, "virtual-root")) 153 else if (!strcmp(name, "virtual-root"))
147 cgit_virtual_root = xstrdup(value); 154 cgit_virtual_root = xstrdup(value);
148 else if (!strcmp(name, "nocache")) 155 else if (!strcmp(name, "nocache"))
149 cgit_nocache = atoi(value); 156 cgit_nocache = atoi(value);
150 else if (!strcmp(name, "snapshots")) 157 else if (!strcmp(name, "snapshots"))
151 cgit_snapshots = atoi(value); 158 cgit_snapshots = cgit_parse_snapshots_mask(value);
152 else if (!strcmp(name, "enable-index-links")) 159 else if (!strcmp(name, "enable-index-links"))
153 cgit_enable_index_links = atoi(value); 160 cgit_enable_index_links = atoi(value);
154 else if (!strcmp(name, "enable-log-filecount")) 161 else if (!strcmp(name, "enable-log-filecount"))
155 cgit_enable_log_filecount = atoi(value); 162 cgit_enable_log_filecount = atoi(value);
156 else if (!strcmp(name, "enable-log-linecount")) 163 else if (!strcmp(name, "enable-log-linecount"))
157 cgit_enable_log_linecount = atoi(value); 164 cgit_enable_log_linecount = atoi(value);
@@ -187,13 +194,13 @@ void cgit_global_config_cb(const char *name, const char *value)
187 cgit_repo->desc = xstrdup(value); 194 cgit_repo->desc = xstrdup(value);
188 else if (cgit_repo && !strcmp(name, "repo.owner")) 195 else if (cgit_repo && !strcmp(name, "repo.owner"))
189 cgit_repo->owner = xstrdup(value); 196 cgit_repo->owner = xstrdup(value);
190 else if (cgit_repo && !strcmp(name, "repo.defbranch")) 197 else if (cgit_repo && !strcmp(name, "repo.defbranch"))
191 cgit_repo->defbranch = xstrdup(value); 198 cgit_repo->defbranch = xstrdup(value);
192 else if (cgit_repo && !strcmp(name, "repo.snapshots")) 199 else if (cgit_repo && !strcmp(name, "repo.snapshots"))
193 cgit_repo->snapshots = cgit_snapshots * atoi(value); 200 cgit_repo->snapshots = cgit_snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
194 else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount")) 201 else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount"))
195 cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value); 202 cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value);
196 else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount")) 203 else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount"))
197 cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value); 204 cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value);
198 else if (cgit_repo && !strcmp(name, "repo.module-link")) 205 else if (cgit_repo && !strcmp(name, "repo.module-link"))
199 cgit_repo->module_link= xstrdup(value); 206 cgit_repo->module_link= xstrdup(value);
diff --git a/ui-commit.c b/ui-commit.c
index 2679b59..50e9e11 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -136,13 +136,12 @@ void inspect_filepair(struct diff_filepair *pair)
136void cgit_print_commit(char *hex) 136void cgit_print_commit(char *hex)
137{ 137{
138 struct commit *commit, *parent; 138 struct commit *commit, *parent;
139 struct commitinfo *info; 139 struct commitinfo *info;
140 struct commit_list *p; 140 struct commit_list *p;
141 unsigned char sha1[20]; 141 unsigned char sha1[20];
142 char *filename;
143 char *tmp; 142 char *tmp;
144 int i; 143 int i;
145 144
146 if (!hex) 145 if (!hex)
147 hex = cgit_query_head; 146 hex = cgit_query_head;
148 curr_rev = hex; 147 curr_rev = hex;
@@ -193,17 +192,15 @@ void cgit_print_commit(char *hex)
193 html(" ("); 192 html(" (");
194 cgit_diff_link("diff", NULL, NULL, cgit_query_head, hex, 193 cgit_diff_link("diff", NULL, NULL, cgit_query_head, hex,
195 sha1_to_hex(p->item->object.sha1), NULL); 194 sha1_to_hex(p->item->object.sha1), NULL);
196 html(")</td></tr>"); 195 html(")</td></tr>");
197 } 196 }
198 if (cgit_repo->snapshots) { 197 if (cgit_repo->snapshots) {
199 htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='"); 198 html("<tr><th>download</th><td colspan='2' class='sha1'>");
200 filename = fmt("%s-%s.zip", cgit_query_repo, hex); 199 cgit_print_snapshot_links(cgit_query_repo,hex,cgit_repo->snapshots);
201 html_attr(cgit_pageurl(cgit_query_repo, "snapshot", 200 html("</td></tr>");
202 fmt("id=%s&amp;name=%s", hex, filename)));
203 htmlf("'>%s</a></td></tr>", filename);
204 } 201 }
205 html("</table>\n"); 202 html("</table>\n");
206 html("<div class='commit-subject'>"); 203 html("<div class='commit-subject'>");
207 html_txt(info->subject); 204 html_txt(info->subject);
208 html("</div>"); 205 html("</div>");
209 html("<div class='commit-msg'>"); 206 html("<div class='commit-msg'>");
diff --git a/ui-shared.c b/ui-shared.c
index fd71c12..ca2ee82 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -54,30 +54,61 @@ char *cgit_repourl(const char *reponame)
54 return fmt("%s/%s/", cgit_virtual_root, reponame); 54 return fmt("%s/%s/", cgit_virtual_root, reponame);
55 } else { 55 } else {
56 return fmt("?r=%s", reponame); 56 return fmt("?r=%s", reponame);
57 } 57 }
58} 58}
59 59
60char *cgit_pageurl(const char *reponame, const char *pagename, 60char *cgit_fileurl(const char *reponame, const char *pagename,
61 const char *query) 61 const char *filename, const char *query)
62{ 62{
63 if (cgit_virtual_root) { 63 if (cgit_virtual_root) {
64 if (query) 64 if (query)
65 return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame, 65 return fmt("%s/%s/%s/%s?%s", cgit_virtual_root, reponame,
66 pagename, query); 66 pagename, filename?filename:"", query);
67 else 67 else
68 return fmt("%s/%s/%s/", cgit_virtual_root, reponame, 68 return fmt("%s/%s/%s/", cgit_virtual_root, reponame,
69 pagename); 69 pagename);
70 } else { 70 } else {
71 if (query) 71 if (query)
72 return fmt("?r=%s&amp;p=%s&amp;%s", reponame, pagename, query); 72 return fmt("?r=%s&amp;p=%s&amp;%s", reponame, pagename, query);
73 else 73 else
74 return fmt("?r=%s&amp;p=%s", reponame, pagename); 74 return fmt("?r=%s&amp;p=%s", reponame, pagename);
75 } 75 }
76} 76}
77 77
78char *cgit_pageurl(const char *reponame, const char *pagename,
79 const char *query)
80{
81 return cgit_fileurl(reponame,pagename,0,query);
82}
83
84const char *cgit_repobasename(const char *reponame)
85{
86 /* I assume we don't need to store more than one repo basename */
87 static char rvbuf[1024];
88 int p;
89 const char *rv;
90 strncpy(rvbuf,reponame,sizeof(rvbuf));
91 if(rvbuf[sizeof(rvbuf)-1])
92 die("cgit_repobasename: truncated repository name '%s'", reponame);
93 p = strlen(rvbuf)-1;
94 /* strip trailing slashes */
95 while(p && rvbuf[p]=='/') rvbuf[p--]=0;
96 /* strip trailing .git */
97 if(p>=3 && !strncmp(&rvbuf[p-3],".git",4)) {
98 p -= 3; rvbuf[p--] = 0;
99 }
100 /* strip more trailing slashes if any */
101 while( p && rvbuf[p]=='/') rvbuf[p--]=0;
102 /* find last slash in the remaining string */
103 rv = strrchr(rvbuf,'/');
104 if(rv)
105 return ++rv;
106 return rvbuf;
107}
108
78char *cgit_currurl() 109char *cgit_currurl()
79{ 110{
80 if (!cgit_virtual_root) 111 if (!cgit_virtual_root)
81 return cgit_script_name; 112 return cgit_script_name;
82 else if (cgit_query_page) 113 else if (cgit_query_page)
83 return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page); 114 return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page);
@@ -389,6 +420,8 @@ void cgit_print_snapshot_start(const char *mimetype, const char *filename,
389 htmlf("Content-Disposition: inline; filename=\"%s\"\n", filename); 420 htmlf("Content-Disposition: inline; filename=\"%s\"\n", filename);
390 htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); 421 htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime));
391 htmlf("Expires: %s\n", http_date(item->st.st_mtime + 422 htmlf("Expires: %s\n", http_date(item->st.st_mtime +
392 ttl_seconds(item->ttl))); 423 ttl_seconds(item->ttl)));
393 html("\n"); 424 html("\n");
394} 425}
426
427/* vim:set sw=8: */
diff --git a/ui-snapshot.c b/ui-snapshot.c
index 2257d6b..d6be55b 100644
--- a/ui-snapshot.c
+++ b/ui-snapshot.c
@@ -5,43 +5,141 @@
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10 10
11static void cgit_print_zip(struct cacheitem *item, const char *hex, 11static int write_compressed_tar_archive(struct archiver_args *args,const char *filter)
12 const char *prefix, const char *filename)
13{ 12{
14 struct archiver_args args; 13 int rw[2];
15 struct commit *commit; 14 pid_t gzpid;
16 unsigned char sha1[20]; 15 int stdout2;
16 int status;
17 int rv;
17 18
18 if (get_sha1(hex, sha1)) { 19 stdout2 = chk_non_negative(dup(STDIN_FILENO), "Preserving STDOUT before compressing");
19 cgit_print_error(fmt("Bad object id: %s", hex)); 20 chk_zero(pipe(rw), "Opening pipe from compressor subprocess");
20 return; 21 gzpid = chk_non_negative(fork(), "Forking compressor subprocess");
22 if(gzpid==0) {
23 /* child */
24 chk_zero(close(rw[1]), "Closing write end of pipe in child");
25 chk_zero(close(STDIN_FILENO), "Closing STDIN");
26 chk_non_negative(dup2(rw[0],STDIN_FILENO), "Redirecting compressor input to stdin");
27 execlp(filter,filter,NULL);
28 _exit(-1);
21 } 29 }
22 commit = lookup_commit_reference(sha1); 30 /* parent */
31 chk_zero(close(rw[0]), "Closing read end of pipe");
32 chk_non_negative(dup2(rw[1],STDOUT_FILENO), "Redirecting output to compressor");
33
34 rv = write_tar_archive(args);
23 35
24 if (!commit) { 36 chk_zero(close(STDOUT_FILENO), "Closing STDOUT redirected to compressor");
25 cgit_print_error(fmt("Not a commit reference: %s", hex)); 37 chk_non_negative(dup2(stdout2,STDOUT_FILENO), "Restoring uncompressed STDOUT");
26 return; 38 chk_zero(close(stdout2), "Closing uncompressed STDOUT");
27 } 39 chk_zero(close(rw[1]), "Closing write end of pipe in parent");
40 chk_positive(waitpid(gzpid,&status,0), "Waiting on compressor process");
41 if(! ( WIFEXITED(status) && WEXITSTATUS(status)==0 ) )
42 cgit_print_error("Failed to compress archive");
28 43
29 memset(&args, 0, sizeof(args)); 44 return rv;
30 args.base = fmt("%s/", prefix);
31 args.tree = commit->tree;
32
33 cgit_print_snapshot_start("application/x-zip", filename, item);
34 write_zip_archive(&args);
35} 45}
36 46
47static int write_tar_gzip_archive(struct archiver_args *args)
48{
49 return write_compressed_tar_archive(args,"gzip");
50}
51static int write_tar_bzip2_archive(struct archiver_args *args)
52{
53 return write_compressed_tar_archive(args,"bzip2");
54}
55
56static const struct snapshot_archive_t {
57 const char *suffix;
58 const char *mimetype;
59 write_archive_fn_t write_func;
60 int bit;
61 }snapshot_archives[] = {
62 { ".zip", "application/x-zip", write_zip_archive, 0x1 },
63 { ".tar.gz", "application/x-tar", write_tar_gzip_archive, 0x2 },
64 { ".tar.bz2", "application/x-tar", write_tar_bzip2_archive, 0x4 },
65 { ".tar", "application/x-tar", write_tar_archive, 0x8 }
66};
37 67
38void cgit_print_snapshot(struct cacheitem *item, const char *hex, 68void cgit_print_snapshot(struct cacheitem *item, const char *hex,
39 const char *format, const char *prefix, 69 const char *prefix, const char *filename,
40 const char *filename) 70 int snapshots)
71{
72 int fnl = strlen(filename);
73 int f;
74 for(f=0;f<(sizeof(snapshot_archives)/sizeof(*snapshot_archives));++f) {
75 const struct snapshot_archive_t* sat = &snapshot_archives[f];
76 int sl;
77 if(!(snapshots&sat->bit)) continue;
78 sl = strlen(sat->suffix);
79 if(fnl<sl || strcmp(&filename[fnl-sl],sat->suffix))
80 continue;
81
82 struct archiver_args args;
83 struct commit *commit;
84 unsigned char sha1[20];
85
86 if(get_sha1(hex, sha1)) {
87 cgit_print_error(fmt("Bad object id: %s", hex));
88 return;
89 }
90 commit = lookup_commit_reference(sha1);
91
92 if(!commit) {
93 cgit_print_error(fmt("Not a commit reference: %s", hex));
94 return;;
95 }
96
97 memset(&args,0,sizeof(args));
98 args.base = fmt("%s/", prefix);
99 args.tree = commit->tree;
100
101 cgit_print_snapshot_start(sat->mimetype, filename, item);
102 (*sat->write_func)(&args);
103 return;
104 }
105 cgit_print_error(fmt("Unsupported snapshot format: %s", filename));
106}
107
108void cgit_print_snapshot_links(const char *repo,const char *hex,int snapshots)
41{ 109{
42 if (!strcmp(format, "zip")) 110 char *filename;
43 cgit_print_zip(item, hex, prefix, filename); 111 int f;
44 else 112 for(f=0;f<(sizeof(snapshot_archives)/sizeof(*snapshot_archives));++f) {
45 cgit_print_error(fmt("Unsupported snapshot format: %s", 113 const struct snapshot_archive_t* sat = &snapshot_archives[f];
46 format)); 114 if(!(snapshots&sat->bit)) continue;
115 filename = fmt("%s-%s%s",cgit_repobasename(repo),hex,sat->suffix);
116 htmlf("<a href='%s'>%s</a><br/>",
117 cgit_fileurl(repo,"snapshot",filename,
118 fmt("id=%s&amp;name=%s",hex,filename)), filename);
119 }
120}
121
122int cgit_parse_snapshots_mask(const char *str)
123{
124 static const char *delim = " \t,:/|;";
125 int f, tl, rv = 0;
126 /* favor legacy setting */
127 if(atoi(str)) return 1;
128 for(;;) {
129 str += strspn(str,delim);
130 tl = strcspn(str,delim);
131 if(!tl)
132 break;
133 for(f=0;f<(sizeof(snapshot_archives)/sizeof(*snapshot_archives));++f) {
134 const struct snapshot_archive_t* sat = &snapshot_archives[f];
135 if(! ( strncmp(sat->suffix,str,tl) && strncmp(sat->suffix+1,str,tl-1) ) ) {
136 rv |= sat->bit;
137 break;
138 }
139 }
140 str += tl;
141 }
142 return rv;
47} 143}
144
145/* vim:set sw=8: */
diff --git a/ui-tree.c b/ui-tree.c
index c5d64ff..75ce449 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -29,12 +29,16 @@ static void print_object(const unsigned char *sha1, char *path)
29 if (!buf) { 29 if (!buf) {
30 cgit_print_error(fmt("Error reading object %s", 30 cgit_print_error(fmt("Error reading object %s",
31 sha1_to_hex(sha1))); 31 sha1_to_hex(sha1)));
32 return; 32 return;
33 } 33 }
34 34
35 html(" blob: <a href='");
36 html_attr(cgit_pageurl(cgit_query_repo, "blob", fmt("id=%s", sha1_to_hex(sha1))));
37 htmlf("'>%s</a>",sha1_to_hex(sha1));
38
35 html("<table class='blob'>\n"); 39 html("<table class='blob'>\n");
36 idx = 0; 40 idx = 0;
37 start = 0; 41 start = 0;
38 lineno = 0; 42 lineno = 0;
39 while(idx < size) { 43 while(idx < size) {
40 if (buf[idx] == '\n') { 44 if (buf[idx] == '\n') {