X-Git-Url: https://gitweb.ps.run/ps-cgit/blobdiff_plain/1a63cfcc3d83919e790e7e279eb35fc75adb0e3c..df90b51bafec24336cf30339b2978ff6df22b075:/ui-shared.c diff --git a/ui-shared.c b/ui-shared.c index aba93e8..aa65988 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -7,6 +7,7 @@ */ #include "cgit.h" +#include "html.h" const char cgit_doctype[] = "tm_hour, tm->tm_min, tm->tm_sec); } -static long ttl_seconds(long ttl) -{ - if (ttl<0) - return 60 * 60 * 24 * 365; - else - return ttl * 60; -} - void cgit_print_error(char *msg) { html("
"); @@ -42,57 +35,276 @@ void cgit_print_error(char *msg) char *cgit_rooturl() { - if (cgit_virtual_root) - return fmt("%s/", cgit_virtual_root); + if (ctx.cfg.virtual_root) + return fmt("%s/", ctx.cfg.virtual_root); else - return cgit_script_name; + return ctx.cfg.script_name; } char *cgit_repourl(const char *reponame) { - if (cgit_virtual_root) { - return fmt("%s/%s/", cgit_virtual_root, reponame); + if (ctx.cfg.virtual_root) { + return fmt("%s/%s/", ctx.cfg.virtual_root, reponame); } else { return fmt("?r=%s", reponame); } } +char *cgit_fileurl(const char *reponame, const char *pagename, + const char *filename, const char *query) +{ + char *tmp; + char *delim; + + if (ctx.cfg.virtual_root) { + tmp = fmt("%s/%s/%s/%s", ctx.cfg.virtual_root, reponame, + pagename, (filename ? filename:"")); + delim = "?"; + } else { + tmp = fmt("?url=%s/%s/%s", reponame, pagename, + (filename ? filename : "")); + delim = "&"; + } + if (query) + tmp = fmt("%s%s%s", tmp, delim, query); + return tmp; +} + char *cgit_pageurl(const char *reponame, const char *pagename, const char *query) { - if (cgit_virtual_root) { - if (query) - return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame, - pagename, 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); + 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); + if (!ctx.cfg.virtual_root) + return ctx.cfg.script_name; + else if (ctx.qry.page) + return fmt("%s/%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo, ctx.qry.page); + else if (ctx.qry.repo) + return fmt("%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo); else - return fmt("%s/", cgit_virtual_root); + return fmt("%s/", ctx.cfg.virtual_root); +} + +static char *repolink(char *title, char *class, char *page, char *head, + char *path) +{ + char *delim = "?"; + + html("url); + if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') + html("/"); + if (page) { + html(page); + html("/"); + if (path) + html_attr(path); + } + } else { + html(ctx.cfg.script_name); + html("?url="); + html_attr(ctx.repo->url); + if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') + html("/"); + if (page) { + html(page); + html("/"); + if (path) + html_attr(path); + } + delim = "&"; + } + if (head && strcmp(head, ctx.repo->defbranch)) { + html(delim); + html("h="); + html_attr(head); + delim = "&"; + } + return fmt("%s", delim); +} + +static void reporevlink(char *page, char *name, char *title, char *class, + char *head, char *rev, char *path) +{ + char *delim; + + delim = repolink(title, class, page, head, path); + if (rev && strcmp(rev, ctx.qry.head)) { + html(delim); + html("id="); + html_attr(rev); + } + html("'>"); + html_txt(name); + html(""); +} + +void cgit_tree_link(char *name, char *title, char *class, char *head, + char *rev, char *path) +{ + reporevlink("tree", name, title, class, head, rev, path); +} + +void cgit_log_link(char *name, char *title, char *class, char *head, + char *rev, char *path, int ofs, char *grep, char *pattern) +{ + char *delim; + + delim = repolink(title, class, "log", head, path); + if (rev && strcmp(rev, ctx.qry.head)) { + html(delim); + html("id="); + html_attr(rev); + delim = "&"; + } + if (grep && pattern) { + html(delim); + html("qt="); + html_attr(grep); + delim = "&"; + html(delim); + html("q="); + html_attr(pattern); + } + if (ofs > 0) { + html(delim); + html("ofs="); + htmlf("%d", ofs); + } + html("'>"); + html_txt(name); + html(""); +} + +void cgit_commit_link(char *name, char *title, char *class, char *head, + char *rev) +{ + if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { + name[ctx.cfg.max_msg_len] = '\0'; + name[ctx.cfg.max_msg_len - 1] = '.'; + name[ctx.cfg.max_msg_len - 2] = '.'; + name[ctx.cfg.max_msg_len - 3] = '.'; + } + reporevlink("commit", name, title, class, head, rev, NULL); } +void cgit_refs_link(char *name, char *title, char *class, char *head, + char *rev, char *path) +{ + reporevlink("refs", name, title, class, head, rev, path); +} + +void cgit_snapshot_link(char *name, char *title, char *class, char *head, + char *rev, char *archivename) +{ + reporevlink("snapshot", name, title, class, head, rev, archivename); +} + +void cgit_diff_link(char *name, char *title, char *class, char *head, + char *new_rev, char *old_rev, char *path) +{ + char *delim; + + delim = repolink(title, class, "diff", head, path); + if (new_rev && strcmp(new_rev, ctx.qry.head)) { + html(delim); + html("id="); + html_attr(new_rev); + delim = "&"; + } + if (old_rev) { + html(delim); + html("id2="); + html_attr(old_rev); + } + html("'>"); + html_txt(name); + html(""); +} + +void cgit_patch_link(char *name, char *title, char *class, char *head, + char *rev) +{ + reporevlink("patch", name, title, class, head, rev, NULL); +} + +void cgit_object_link(struct object *obj) +{ + char *page, *arg, *url; + + if (obj->type == OBJ_COMMIT) { + cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL, + ctx.qry.head, sha1_to_hex(obj->sha1)); + return; + } else if (obj->type == OBJ_TREE) { + page = "tree"; + arg = "id"; + } else if (obj->type == OBJ_TAG) { + page = "tag"; + arg = "id"; + } else { + page = "blob"; + arg = "id"; + } + + url = cgit_pageurl(ctx.qry.repo, page, + fmt("%s=%s", arg, sha1_to_hex(obj->sha1))); + html_link_open(url, NULL, NULL); + htmlf("%s %s", typename(obj->type), + sha1_to_hex(obj->sha1)); + html_link_close(); +} void cgit_print_date(time_t secs, char *format) { char buf[64]; struct tm *time; + if (!secs) + return; time = gmtime(&secs); strftime(buf, sizeof(buf)-1, format, time); html_txt(buf); @@ -102,6 +314,8 @@ void cgit_print_age(time_t t, time_t max_relative, char *format) { time_t now, secs; + if (!t) + return; time(&now); secs = now - t; @@ -139,22 +353,34 @@ void cgit_print_age(time_t t, time_t max_relative, char *format) secs * 1.0 / TM_YEAR); } -void cgit_print_docstart(char *title, struct cacheitem *item) +void cgit_print_http_headers(struct cgit_context *ctx) { - html("Content-Type: text/html; charset=utf-8\n"); - 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))); + if (ctx->page.mimetype && ctx->page.charset) + htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype, + ctx->page.charset); + else if (ctx->page.mimetype) + htmlf("Content-Type: %s\n", ctx->page.mimetype); + if (ctx->page.filename) + htmlf("Content-Disposition: inline; filename=\"%s\"\n", + ctx->page.filename); + htmlf("Last-Modified: %s\n", http_date(ctx->page.modified)); + htmlf("Expires: %s\n", http_date(ctx->page.expires)); html("\n"); +} + +void cgit_print_docstart(struct cgit_context *ctx) +{ html(cgit_doctype); - html("\n"); + html("\n"); html("\n"); html(""); - html_txt(title); + html_txt(ctx->page.title); html("\n"); - htmlf("\n", cgit_version); + htmlf("\n", cgit_version); + if (ctx->cfg.robots && *ctx->cfg.robots) + htmlf("\n", ctx->cfg.robots); html("\n"); html("\n"); html("\n"); @@ -162,60 +388,204 @@ void cgit_print_docstart(char *title, struct cacheitem *item) void cgit_print_docend() { - html(""); - html("\n\n"); -} - -void cgit_print_pageheader(char *title, int show_search) -{ - html(""); - html(""); - html(""); - html("\n\n
"); - htmlf("root", cgit_rooturl()); - if (cgit_query_repo) { - htmlf(" : ", cgit_repourl(cgit_repo->url)); - html_txt(cgit_repo->name); - htmlf(" : %s", title); - } - html("
\n\n\n"); +} + +int print_branch_option(const char *refname, const unsigned char *sha1, + int flags, void *cb_data) +{ + char *name = (char *)refname; + html_option(name, name, ctx.qry.head); + return 0; +} + +int print_archive_ref(const char *refname, const unsigned char *sha1, + int flags, void *cb_data) +{ + struct tag *tag; + struct taginfo *info; + struct object *obj; + char buf[256], *url; + unsigned char fileid[20]; + int *header = (int *)cb_data; + + if (prefixcmp(refname, "refs/archives")) + return 0; + strncpy(buf, refname+14, sizeof(buf)); + obj = parse_object(sha1); + if (!obj) + return 1; + if (obj->type == OBJ_TAG) { + tag = lookup_tag(sha1); + if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) + return 0; + hashcpy(fileid, tag->tagged->sha1); + } else if (obj->type != OBJ_BLOB) { + return 0; + } else { + hashcpy(fileid, sha1); + } + if (!*header) { + html("

download

\n"); + *header = 1; + } + url = cgit_pageurl(ctx.qry.repo, "blob", + fmt("id=%s&path=%s", sha1_to_hex(fileid), + buf)); + html_link_open(url, NULL, "menu"); + html_txt(strlpart(buf, 20)); + html_link_close(); + return 0; +} + +void add_hidden_formfields(int incl_head, int incl_search, char *page) +{ + char *url; + + if (!ctx.cfg.virtual_root) { + url = fmt("%s/%s", ctx.qry.repo, page); + if (ctx.qry.path) + url = fmt("%s/%s", url, ctx.qry.path); + html_hidden("url", url); + } + + if (incl_head && strcmp(ctx.qry.head, ctx.repo->defbranch)) + html_hidden("h", ctx.qry.head); + + if (ctx.qry.sha1) + html_hidden("id", ctx.qry.sha1); + if (ctx.qry.sha2) + html_hidden("id2", ctx.qry.sha2); + + if (incl_search) { + if (ctx.qry.grep) + html_hidden("qt", ctx.qry.grep); + if (ctx.qry.search) + html_hidden("q", ctx.qry.search); + } +} + +void cgit_print_pageheader(struct cgit_context *ctx) +{ + static const char *default_info = "This is cgit, a fast webinterface for git repositories"; + int header = 0; + char *url; + + html("\n"); + html("\n"); + + html("
\n"); +} + +void cgit_print_filemode(unsigned short mode) +{ + if (S_ISDIR(mode)) + html("d"); + else if (S_ISLNK(mode)) + html("l"); + else if (S_ISGITLINK(mode)) + html("m"); + else + html("-"); + html_fileperm(mode >> 6); + html_fileperm(mode >> 3); + html_fileperm(mode); +} + +void cgit_print_snapshot_links(const char *repo, const char *head, + const char *hex, int snapshots) +{ + const struct cgit_snapshot_format* f; + char *filename; + + for (f = cgit_snapshot_formats; f->suffix; f++) { + if (!(snapshots & f->bit)) + continue; + filename = fmt("%s-%s%s", cgit_repobasename(repo), hex, + f->suffix); + cgit_snapshot_link(filename, NULL, NULL, (char *)head, + (char *)hex, filename); + html("
"); + } }