author | Lars Hjemli <hjemli@gmail.com> | 2007-07-22 21:57:48 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2007-07-22 21:57:56 (UTC) |
commit | 1d4aaff696ee1b9085dda0f0f3d84d9d20d96db0 (patch) (side-by-side diff) | |
tree | 6674c5168d967c3efdbf8f445e7e975d54e43629 | |
parent | 4e9107abfe8d3edff17826875b417bcf40dc7390 (diff) | |
parent | d6b01dac856efda565d4085e77826fd9ac83348a (diff) | |
download | cgit-1d4aaff696ee1b9085dda0f0f3d84d9d20d96db0.zip cgit-1d4aaff696ee1b9085dda0f0f3d84d9d20d96db0.tar.gz cgit-1d4aaff696ee1b9085dda0f0f3d84d9d20d96db0.tar.bz2 |
Merge branch 'master' of git://git.klever.net/patchwork/cgit
* 'master' of git://git.klever.net/patchwork/cgit:
link raw blob from tree file view
fix: changed view link to blob in summary.
allow selective enabling of snapshots
shorten snapshot names to repo basename
introduce cgit_repobasename
added snapshot filename to the link
add plain uncompressed tar snapshort format
introduced .tar.bz2 snapshots
compress .tar.gz using gzip as a filter
added a chk_non_negative check
css: adjust vertical-align of commit info th cells
add support for snapshot tarballs
Conflicts:
ui-summary.c
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | cgit.c | 6 | ||||
-rw-r--r-- | cgit.css | 1 | ||||
-rw-r--r-- | cgit.h | 11 | ||||
-rw-r--r-- | cgitrc | 5 | ||||
-rw-r--r-- | shared.c | 11 | ||||
-rw-r--r-- | ui-commit.c | 9 | ||||
-rw-r--r-- | ui-shared.c | 41 | ||||
-rw-r--r-- | ui-snapshot.c | 124 | ||||
-rw-r--r-- | ui-tree.c | 4 |
9 files changed, 181 insertions, 31 deletions
@@ -55,34 +55,36 @@ static void cgit_print_repo_page(struct cacheitem *item) if (chdir(cgit_repo->path)) { title = fmt("%s - %s", cgit_root_title, "Bad request"); cgit_print_docstart(title, item); cgit_print_pageheader(title, 0); cgit_print_error(fmt("Unable to scan repository: %s", strerror(errno))); cgit_print_docend(); return; } title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc); show_search = 0; setenv("GIT_DIR", cgit_repo->path, 1); if ((cgit_cmd == CMD_SNAPSHOT) && cgit_repo->snapshots) { - cgit_print_snapshot(item, cgit_query_sha1, "zip", - cgit_repo->url, cgit_query_name); + cgit_print_snapshot(item, cgit_query_sha1, + cgit_repobasename(cgit_repo->url), + cgit_query_name, + cgit_repo->snapshots ); return; } if (cgit_cmd == CMD_BLOB) { cgit_print_blob(item, cgit_query_sha1, cgit_query_path); return; } show_search = (cgit_cmd == CMD_LOG); cgit_print_docstart(title, item); if (!cgit_cmd) { cgit_print_pageheader("summary", show_search); cgit_print_summary(); cgit_print_docend(); return; } @@ -218,32 +218,33 @@ table.blob td.txt { padding-left: 0.5em; } table.nowrap td { white-space: nowrap; } table.commit-info { border-collapse: collapse; margin-top: 1.5em; } table.commit-info th { text-align: left; font-weight: normal; padding: 0.1em 1em 0.1em 0.1em; + vertical-align: top; } table.commit-info td { font-weight: normal; padding: 0.1em 1em 0.1em 0.1em; } div.commit-subject { font-weight: bold; font-size: 125%; margin: 1.5em 0em 0.5em 0em; padding: 0em; } div.commit-msg { white-space: pre; @@ -144,32 +144,33 @@ extern char *cgit_query_head; extern char *cgit_query_sha1; extern char *cgit_query_sha2; extern char *cgit_query_path; extern char *cgit_query_name; extern int cgit_query_ofs; extern int htmlfd; extern int cgit_get_cmd_index(const char *cmd); extern struct repoinfo *cgit_get_repoinfo(const char *url); extern void cgit_global_config_cb(const char *name, const char *value); extern void cgit_repo_config_cb(const char *name, const char *value); extern void cgit_querystring_cb(const char *name, const char *value); extern int chk_zero(int result, char *msg); extern int chk_positive(int result, char *msg); +extern int chk_non_negative(int result, char *msg); extern int hextoint(char c); extern char *trim_end(const char *str, char c); extern void *cgit_free_commitinfo(struct commitinfo *info); extern int cgit_diff_files(const unsigned char *old_sha1, const unsigned char *new_sha1, linediff_fn fn); extern void cgit_diff_tree(const unsigned char *old_sha1, const unsigned char *new_sha1, filepair_fn fn); extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); @@ -187,53 +188,59 @@ extern void html_filemode(unsigned short mode); extern int html_include(const char *filename); extern int cgit_read_config(const char *filename, configfn fn); extern int cgit_parse_query(char *txt, configfn fn); extern struct commitinfo *cgit_parse_commit(struct commit *commit); extern struct taginfo *cgit_parse_tag(struct tag *tag); extern void cgit_parse_url(const char *url); extern char *cache_safe_filename(const char *unsafe); extern int cache_lock(struct cacheitem *item); extern int cache_unlock(struct cacheitem *item); extern int cache_cancel_lock(struct cacheitem *item); extern int cache_exist(struct cacheitem *item); extern int cache_expired(struct cacheitem *item); extern char *cgit_repourl(const char *reponame); +extern char *cgit_fileurl(const char *reponame, const char *pagename, + const char *filename, const char *query); extern char *cgit_pageurl(const char *reponame, const char *pagename, const char *query); +extern const char *cgit_repobasename(const char *reponame); + extern void cgit_tree_link(char *name, char *title, char *class, char *head, char *rev, char *path); extern void cgit_log_link(char *name, char *title, char *class, char *head, char *rev, char *path, int ofs); extern void cgit_commit_link(char *name, char *title, char *class, char *head, char *rev); extern void cgit_diff_link(char *name, char *title, char *class, char *head, char *new_rev, char *old_rev, char *path); extern void cgit_object_link(struct object *obj); extern void cgit_print_error(char *msg); extern void cgit_print_date(time_t secs, char *format); extern void cgit_print_age(time_t t, time_t max_relative, char *format); extern void cgit_print_docstart(char *title, struct cacheitem *item); extern void cgit_print_docend(); extern void cgit_print_pageheader(char *title, int show_search); extern void cgit_print_snapshot_start(const char *mimetype, const char *filename, struct cacheitem *item); extern void cgit_print_repolist(struct cacheitem *item); extern void cgit_print_summary(); extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path, int pager); extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); extern void cgit_print_tree(const char *rev, char *path); extern void cgit_print_commit(char *hex); extern void cgit_print_tag(char *revname); extern void cgit_print_diff(const char *new_hex, const char *old_hex); extern void cgit_print_snapshot(struct cacheitem *item, const char *hex, - const char *format, const char *prefix, - const char *filename); + const char *prefix, const char *filename, + int snapshot); +extern void cgit_print_snapshot_links(const char *repo, const char *hex,int snapshots); +extern int cgit_parse_snapshots_mask(const char *str); #endif /* CGIT_H */ @@ -1,27 +1,28 @@ ## ## cgitrc: template for /etc/cgitrc ## ## Uncomment and set to 1 to deactivate caching of generated pages. Mostly ## usefull for testing. #nocache=0 -## Enable/disable snapshots by default. This can be overridden per repo +## Set allowed snapshot types by default. Can be overridden per repo +# can be any combination of zip/tar.gz/tar.bz2/tar #snapshots=0 ## Enable/disable extra links to summary/log/tree per repo on index page #enable-index-links=0 ## Enable/disable display of 'number of files changed' in log view #enable-log-filecount=0 ## Enable/disable display of 'number of lines changed' in log view #enable-log-linecount=0 ## Enable/disable display of HEAD shortlog in summary view. Set it to maximum @@ -100,21 +101,21 @@ ## ttl for other dynamic pages #cache-dynamic-ttl=5 ## ttl for static pages (addressed by SHA-1) #cache-static-ttl=-1 ## Example repository entry. Required values are repo.url and repo.path (each ## repository section must start with repo.url). #repo.url=cgit #repo.name=cgit #repo.desc=the caching cgi for git #repo.path=/pub/git/cgit #repo.owner=Lars Hjemli -#repo.snapshots=1 # override a sitewide snapshot-setting +#repo.snapshots=tar.bz2 # override a sitewide snapshot-setting #repo.enable-log-filecount=0 # override the default filecount setting #repo.enable-log-linecount=0 # override the default linecount setting #repo.module-link=/git/%s/commit/?id=%s # override the standard module-link #repo.readme=info/web/readme # specify a file to include on summary page @@ -73,32 +73,39 @@ int cgit_get_cmd_index(const char *cmd) } int chk_zero(int result, char *msg) { if (result != 0) die("%s: %s", msg, strerror(errno)); return result; } int chk_positive(int result, char *msg) { if (result <= 0) die("%s: %s", msg, strerror(errno)); return result; } +int chk_non_negative(int result, char *msg) +{ + if (result < 0) + die("%s: %s",msg, strerror(errno)); + return result; +} + struct repoinfo *add_repo(const char *url) { struct repoinfo *ret; if (++cgit_repolist.count > cgit_repolist.length) { if (cgit_repolist.length == 0) cgit_repolist.length = 8; else cgit_repolist.length *= 2; cgit_repolist.repos = xrealloc(cgit_repolist.repos, cgit_repolist.length * sizeof(struct repoinfo)); } ret = &cgit_repolist.repos[cgit_repolist.count-1]; ret->url = xstrdup(url); @@ -135,33 +142,33 @@ void cgit_global_config_cb(const char *name, const char *value) cgit_root_title = xstrdup(value); else if (!strcmp(name, "css")) cgit_css = xstrdup(value); else if (!strcmp(name, "logo")) cgit_logo = xstrdup(value); else if (!strcmp(name, "index-header")) cgit_index_header = xstrdup(value); else if (!strcmp(name, "logo-link")) cgit_logo_link = xstrdup(value); else if (!strcmp(name, "module-link")) cgit_module_link = xstrdup(value); else if (!strcmp(name, "virtual-root")) cgit_virtual_root = xstrdup(value); else if (!strcmp(name, "nocache")) cgit_nocache = atoi(value); else if (!strcmp(name, "snapshots")) - cgit_snapshots = atoi(value); + cgit_snapshots = cgit_parse_snapshots_mask(value); else if (!strcmp(name, "enable-index-links")) cgit_enable_index_links = atoi(value); else if (!strcmp(name, "enable-log-filecount")) cgit_enable_log_filecount = atoi(value); else if (!strcmp(name, "enable-log-linecount")) cgit_enable_log_linecount = atoi(value); else if (!strcmp(name, "cache-root")) cgit_cache_root = xstrdup(value); else if (!strcmp(name, "cache-root-ttl")) cgit_cache_root_ttl = atoi(value); else if (!strcmp(name, "cache-repo-ttl")) cgit_cache_repo_ttl = atoi(value); else if (!strcmp(name, "cache-static-ttl")) cgit_cache_static_ttl = atoi(value); else if (!strcmp(name, "cache-dynamic-ttl")) cgit_cache_dynamic_ttl = atoi(value); @@ -177,33 +184,33 @@ void cgit_global_config_cb(const char *name, const char *value) cgit_agefile = xstrdup(value); else if (!strcmp(name, "repo.group")) cgit_repo_group = xstrdup(value); else if (!strcmp(name, "repo.url")) cgit_repo = add_repo(value); else if (!strcmp(name, "repo.name")) cgit_repo->name = xstrdup(value); else if (cgit_repo && !strcmp(name, "repo.path")) cgit_repo->path = xstrdup(value); else if (cgit_repo && !strcmp(name, "repo.desc")) cgit_repo->desc = xstrdup(value); else if (cgit_repo && !strcmp(name, "repo.owner")) cgit_repo->owner = xstrdup(value); else if (cgit_repo && !strcmp(name, "repo.defbranch")) cgit_repo->defbranch = xstrdup(value); else if (cgit_repo && !strcmp(name, "repo.snapshots")) - cgit_repo->snapshots = cgit_snapshots * atoi(value); + cgit_repo->snapshots = cgit_snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount")) cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value); else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount")) cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value); else if (cgit_repo && !strcmp(name, "repo.module-link")) cgit_repo->module_link= xstrdup(value); else if (cgit_repo && !strcmp(name, "repo.readme") && value != NULL) { if (*value == '/') cgit_repo->readme = xstrdup(value); else cgit_repo->readme = xstrdup(fmt("%s/%s", cgit_repo->path, value)); } else if (!strcmp(name, "include")) cgit_read_config(value, cgit_global_config_cb); } void cgit_querystring_cb(const char *name, const char *value) diff --git a/ui-commit.c b/ui-commit.c index 2679b59..50e9e11 100644 --- a/ui-commit.c +++ b/ui-commit.c @@ -126,33 +126,32 @@ void inspect_filepair(struct diff_filepair *pair) items[files-1].new_path = xstrdup(pair->two->path); items[files-1].added = lines_added; items[files-1].removed = lines_removed; if (lines_added + lines_removed > max_changes) max_changes = lines_added + lines_removed; total_adds += lines_added; total_rems += lines_removed; } void cgit_print_commit(char *hex) { struct commit *commit, *parent; struct commitinfo *info; struct commit_list *p; unsigned char sha1[20]; - char *filename; char *tmp; int i; if (!hex) hex = cgit_query_head; curr_rev = hex; if (get_sha1(hex, sha1)) { cgit_print_error(fmt("Bad object id: %s", hex)); return; } commit = lookup_commit_reference(sha1); if (!commit) { cgit_print_error(fmt("Bad commit reference: %s", hex)); return; } @@ -183,37 +182,35 @@ void cgit_print_commit(char *hex) if (!parent) { html("<tr><td colspan='3'>"); cgit_print_error("Error reading parent commit"); html("</td></tr>"); continue; } html("<tr><th>parent</th>" "<td colspan='2' class='sha1'>"); cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, cgit_query_head, sha1_to_hex(p->item->object.sha1)); html(" ("); cgit_diff_link("diff", NULL, NULL, cgit_query_head, hex, sha1_to_hex(p->item->object.sha1), NULL); html(")</td></tr>"); } if (cgit_repo->snapshots) { - htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='"); - filename = fmt("%s-%s.zip", cgit_query_repo, hex); - html_attr(cgit_pageurl(cgit_query_repo, "snapshot", - fmt("id=%s&name=%s", hex, filename))); - htmlf("'>%s</a></td></tr>", filename); + html("<tr><th>download</th><td colspan='2' class='sha1'>"); + cgit_print_snapshot_links(cgit_query_repo,hex,cgit_repo->snapshots); + html("</td></tr>"); } html("</table>\n"); html("<div class='commit-subject'>"); html_txt(info->subject); html("</div>"); html("<div class='commit-msg'>"); html_txt(info->msg); html("</div>"); if (!(commit->parents && commit->parents->next && commit->parents->next->next)) { html("<div class='diffstat-header'>Diffstat</div>"); html("<table class='diffstat'>"); max_changes = 0; cgit_diff_commit(commit, inspect_filepair); for(i = 0; i<files; i++) print_fileinfo(&items[i]); html("</table>"); diff --git a/ui-shared.c b/ui-shared.c index fd71c12..ca2ee82 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -44,50 +44,81 @@ char *cgit_rooturl() { if (cgit_virtual_root) return fmt("%s/", cgit_virtual_root); else return cgit_script_name; } char *cgit_repourl(const char *reponame) { if (cgit_virtual_root) { return fmt("%s/%s/", cgit_virtual_root, reponame); } else { return fmt("?r=%s", reponame); } } -char *cgit_pageurl(const char *reponame, const char *pagename, - const char *query) +char *cgit_fileurl(const char *reponame, const char *pagename, + const char *filename, const char *query) { if (cgit_virtual_root) { if (query) - return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame, - pagename, query); + return fmt("%s/%s/%s/%s?%s", cgit_virtual_root, reponame, + pagename, filename?filename:"", query); else return fmt("%s/%s/%s/", cgit_virtual_root, reponame, pagename); } else { if (query) return fmt("?r=%s&p=%s&%s", reponame, pagename, query); else return fmt("?r=%s&p=%s", reponame, pagename); } } +char *cgit_pageurl(const char *reponame, const char *pagename, + const char *query) +{ + return cgit_fileurl(reponame,pagename,0,query); +} + +const char *cgit_repobasename(const char *reponame) +{ + /* I assume we don't need to store more than one repo basename */ + static char rvbuf[1024]; + int p; + const char *rv; + strncpy(rvbuf,reponame,sizeof(rvbuf)); + if(rvbuf[sizeof(rvbuf)-1]) + die("cgit_repobasename: truncated repository name '%s'", reponame); + p = strlen(rvbuf)-1; + /* strip trailing slashes */ + while(p && rvbuf[p]=='/') rvbuf[p--]=0; + /* strip trailing .git */ + if(p>=3 && !strncmp(&rvbuf[p-3],".git",4)) { + p -= 3; rvbuf[p--] = 0; + } + /* strip more trailing slashes if any */ + while( p && rvbuf[p]=='/') rvbuf[p--]=0; + /* find last slash in the remaining string */ + rv = strrchr(rvbuf,'/'); + if(rv) + return ++rv; + return rvbuf; +} + char *cgit_currurl() { if (!cgit_virtual_root) return cgit_script_name; else if (cgit_query_page) return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page); else if (cgit_query_repo) return fmt("%s/%s/", cgit_virtual_root, cgit_query_repo); else return fmt("%s/", cgit_virtual_root); } static char *repolink(char *title, char *class, char *page, char *head, char *path) { char *delim = "?"; @@ -379,16 +410,18 @@ void cgit_print_pageheader(char *title, int show_search) html("'/></form>"); } html("</td></tr>"); html("<tr><td id='content' colspan='2'>"); } void cgit_print_snapshot_start(const char *mimetype, const char *filename, struct cacheitem *item) { htmlf("Content-Type: %s\n", mimetype); htmlf("Content-Disposition: inline; filename=\"%s\"\n", filename); htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); htmlf("Expires: %s\n", http_date(item->st.st_mtime + ttl_seconds(item->ttl))); html("\n"); } + +/* 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 @@ -1,47 +1,145 @@ /* ui-snapshot.c: generate snapshot of a commit * * Copyright (C) 2006 Lars Hjemli * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */ #include "cgit.h" -static void cgit_print_zip(struct cacheitem *item, const char *hex, - const char *prefix, const char *filename) +static int write_compressed_tar_archive(struct archiver_args *args,const char *filter) { + int rw[2]; + pid_t gzpid; + int stdout2; + int status; + int rv; + + stdout2 = chk_non_negative(dup(STDIN_FILENO), "Preserving STDOUT before compressing"); + chk_zero(pipe(rw), "Opening pipe from compressor subprocess"); + gzpid = chk_non_negative(fork(), "Forking compressor subprocess"); + if(gzpid==0) { + /* child */ + chk_zero(close(rw[1]), "Closing write end of pipe in child"); + chk_zero(close(STDIN_FILENO), "Closing STDIN"); + chk_non_negative(dup2(rw[0],STDIN_FILENO), "Redirecting compressor input to stdin"); + execlp(filter,filter,NULL); + _exit(-1); + } + /* parent */ + chk_zero(close(rw[0]), "Closing read end of pipe"); + chk_non_negative(dup2(rw[1],STDOUT_FILENO), "Redirecting output to compressor"); + + rv = write_tar_archive(args); + + chk_zero(close(STDOUT_FILENO), "Closing STDOUT redirected to compressor"); + chk_non_negative(dup2(stdout2,STDOUT_FILENO), "Restoring uncompressed STDOUT"); + chk_zero(close(stdout2), "Closing uncompressed STDOUT"); + chk_zero(close(rw[1]), "Closing write end of pipe in parent"); + chk_positive(waitpid(gzpid,&status,0), "Waiting on compressor process"); + if(! ( WIFEXITED(status) && WEXITSTATUS(status)==0 ) ) + cgit_print_error("Failed to compress archive"); + + return rv; +} + +static int write_tar_gzip_archive(struct archiver_args *args) +{ + return write_compressed_tar_archive(args,"gzip"); +} +static int write_tar_bzip2_archive(struct archiver_args *args) +{ + return write_compressed_tar_archive(args,"bzip2"); +} + +static const struct snapshot_archive_t { + const char *suffix; + const char *mimetype; + write_archive_fn_t write_func; + int bit; +} snapshot_archives[] = { + { ".zip", "application/x-zip", write_zip_archive, 0x1 }, + { ".tar.gz", "application/x-tar", write_tar_gzip_archive, 0x2 }, + { ".tar.bz2", "application/x-tar", write_tar_bzip2_archive, 0x4 }, + { ".tar", "application/x-tar", write_tar_archive, 0x8 } +}; + +void cgit_print_snapshot(struct cacheitem *item, const char *hex, + const char *prefix, const char *filename, + int snapshots) +{ + int fnl = strlen(filename); + int f; + for(f=0;f<(sizeof(snapshot_archives)/sizeof(*snapshot_archives));++f) { + const struct snapshot_archive_t* sat = &snapshot_archives[f]; + int sl; + if(!(snapshots&sat->bit)) continue; + sl = strlen(sat->suffix); + if(fnl<sl || strcmp(&filename[fnl-sl],sat->suffix)) + continue; + struct archiver_args args; struct commit *commit; unsigned char sha1[20]; if (get_sha1(hex, sha1)) { cgit_print_error(fmt("Bad object id: %s", hex)); return; } commit = lookup_commit_reference(sha1); if (!commit) { cgit_print_error(fmt("Not a commit reference: %s", hex)); - return; + return;; } memset(&args, 0, sizeof(args)); args.base = fmt("%s/", prefix); args.tree = commit->tree; - cgit_print_snapshot_start("application/x-zip", filename, item); - write_zip_archive(&args); + cgit_print_snapshot_start(sat->mimetype, filename, item); + (*sat->write_func)(&args); + return; + } + cgit_print_error(fmt("Unsupported snapshot format: %s", filename)); } +void cgit_print_snapshot_links(const char *repo,const char *hex,int snapshots) +{ + char *filename; + int f; + for(f=0;f<(sizeof(snapshot_archives)/sizeof(*snapshot_archives));++f) { + const struct snapshot_archive_t* sat = &snapshot_archives[f]; + if(!(snapshots&sat->bit)) continue; + filename = fmt("%s-%s%s",cgit_repobasename(repo),hex,sat->suffix); + htmlf("<a href='%s'>%s</a><br/>", + cgit_fileurl(repo,"snapshot",filename, + fmt("id=%s&name=%s",hex,filename)), filename); + } +} -void cgit_print_snapshot(struct cacheitem *item, const char *hex, - const char *format, const char *prefix, - const char *filename) +int cgit_parse_snapshots_mask(const char *str) { - if (!strcmp(format, "zip")) - cgit_print_zip(item, hex, prefix, filename); - else - cgit_print_error(fmt("Unsupported snapshot format: %s", - format)); + static const char *delim = " \t,:/|;"; + int f, tl, rv = 0; + /* favor legacy setting */ + if(atoi(str)) return 1; + for(;;) { + str += strspn(str,delim); + tl = strcspn(str,delim); + if(!tl) + break; + for(f=0;f<(sizeof(snapshot_archives)/sizeof(*snapshot_archives));++f) { + const struct snapshot_archive_t* sat = &snapshot_archives[f]; + if(! ( strncmp(sat->suffix,str,tl) && strncmp(sat->suffix+1,str,tl-1) ) ) { + rv |= sat->bit; + break; + } } + str += tl; + } + return rv; +} + +/* vim:set sw=8: */ @@ -19,32 +19,36 @@ static void print_object(const unsigned char *sha1, char *path) unsigned long size, lineno, start, idx; type = sha1_object_info(sha1, &size); if (type == OBJ_BAD) { cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(sha1))); return; } buf = read_sha1_file(sha1, &type, &size); if (!buf) { cgit_print_error(fmt("Error reading object %s", sha1_to_hex(sha1))); return; } + html(" blob: <a href='"); + html_attr(cgit_pageurl(cgit_query_repo, "blob", fmt("id=%s", sha1_to_hex(sha1)))); + htmlf("'>%s</a>",sha1_to_hex(sha1)); + html("<table class='blob'>\n"); idx = 0; start = 0; lineno = 0; while(idx < size) { if (buf[idx] == '\n') { buf[idx] = '\0'; htmlf("<tr><td class='no'>%d</td><td class='txt'>", ++lineno); html_txt(buf + start); html("</td></tr>\n"); start = idx + 1; } idx++; } html("</table>\n"); |