X-Git-Url: https://gitweb.ps.run/ps-cgit/blobdiff_plain/0c8dd9c4bcc7a1a7a49f4eca1f3eb869d0995ea2..ed3497b0de6634350cd17b320538fba918d4084c:/ui-shared.c diff --git a/ui-shared.c b/ui-shared.c index e4bb98f..abe15cd 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -1,12 +1,15 @@ /* ui-shared.c: common web output functions * - * Copyright (C) 2006 Lars Hjemli + * Copyright (C) 2006-2014 cgit Development Team * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */ #include "cgit.h" +#include "ui-shared.h" +#include "cmd.h" +#include "html.h" const char cgit_doctype[] = "tm_wday], - tm->tm_mday, month[tm->tm_mon], 1900+tm->tm_year, + tm->tm_mday, month[tm->tm_mon], 1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec); } -static long ttl_seconds(long ttl) +void cgit_print_error(const char *fmt, ...) { - if (ttl<0) - return 60 * 60 * 24 * 365; - else - return ttl * 60; + va_list ap; + va_start(ap, fmt); + cgit_vprint_error(fmt, ap); + va_end(ap); } -void cgit_print_error(char *msg) +void cgit_vprint_error(const char *fmt, va_list ap) { + va_list cp; html("
"); - html_txt(msg); + va_copy(cp, ap); + html_vtxtf(fmt, cp); + va_end(cp); html("
\n"); } -char *cgit_rooturl() +const char *cgit_httpscheme() { - if (cgit_virtual_root) - return fmt("%s/", cgit_virtual_root); + if (ctx.env.https && !strcmp(ctx.env.https, "on")) + return "https://"; else - return cgit_script_name; + return "http://"; +} + +const char *cgit_hosturl() +{ + if (ctx.env.http_host) + return ctx.env.http_host; + if (!ctx.env.server_name) + return NULL; + if (!ctx.env.server_port || atoi(ctx.env.server_port) == 80) + return ctx.env.server_name; + return fmtalloc("%s:%s", ctx.env.server_name, ctx.env.server_port); +} + +const char *cgit_rooturl() +{ + if (ctx.cfg.virtual_root) + return ctx.cfg.virtual_root; + else + return ctx.cfg.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); - } + if (ctx.cfg.virtual_root) + return fmtalloc("%s%s/", ctx.cfg.virtual_root, reponame); + else + return fmtalloc("?r=%s", reponame); } 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?%s", cgit_virtual_root, reponame, - pagename, filename?filename:"", query); - else - return fmt("%s/%s/%s/", cgit_virtual_root, reponame, - pagename); + struct strbuf sb = STRBUF_INIT; + char *delim; + + if (ctx.cfg.virtual_root) { + strbuf_addf(&sb, "%s%s/%s/%s", ctx.cfg.virtual_root, reponame, + pagename, (filename ? filename:"")); + delim = "?"; } else { - if (query) - return fmt("?r=%s&p=%s&%s", reponame, pagename, query); - else - return fmt("?r=%s&p=%s", reponame, pagename); + strbuf_addf(&sb, "?url=%s/%s/%s", reponame, pagename, + (filename ? filename : "")); + delim = "&"; } + if (query) + strbuf_addf(&sb, "%s%s", delim, query); + return strbuf_detach(&sb, NULL); } char *cgit_pageurl(const char *reponame, const char *pagename, const char *query) { - return cgit_fileurl(reponame,pagename,0,query); + return cgit_fileurl(reponame, pagename, 0, query); } const char *cgit_repobasename(const char *reponame) @@ -87,39 +113,85 @@ const char *cgit_repobasename(const char *reponame) static char rvbuf[1024]; int p; const char *rv; - strncpy(rvbuf,reponame,sizeof(rvbuf)); - if(rvbuf[sizeof(rvbuf)-1]) + 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; + while (p && rvbuf[p] == '/') rvbuf[p--] = 0; /* strip trailing .git */ - if(p>=3 && !strncmp(&rvbuf[p-3],".git",4)) { + if (p >= 3 && !prefixcmp(&rvbuf[p-3], ".git")) { p -= 3; rvbuf[p--] = 0; } /* strip more trailing slashes if any */ - while( p && rvbuf[p]=='/') rvbuf[p--]=0; + while ( p && rvbuf[p] == '/') rvbuf[p--] = 0; /* find last slash in the remaining string */ rv = strrchr(rvbuf,'/'); - if(rv) + if (rv) return ++rv; return rvbuf; } -char *cgit_currurl() +static void site_url(const char *page, const char *search, const char *sort, int ofs) { - 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); + char *delim = "?"; + + if (ctx.cfg.virtual_root) + html_attr(ctx.cfg.virtual_root); else - return fmt("%s/", cgit_virtual_root); + html_url_path(ctx.cfg.script_name); + + if (page) { + htmlf("?p=%s", page); + delim = "&"; + } + if (search) { + html(delim); + html("q="); + html_attr(search); + delim = "&"; + } + if (sort) { + html(delim); + html("s="); + html_attr(sort); + delim = "&"; + } + if (ofs) { + html(delim); + htmlf("ofs=%d", ofs); + } +} + +static void site_link(const char *page, const char *name, const char *title, + const char *class, const char *search, const char *sort, int ofs) +{ + html(""); + html_txt(name); + html(""); +} + +void cgit_index_link(const char *name, const char *title, const char *class, + const char *pattern, const char *sort, int ofs) +{ + site_link(NULL, name, title, class, pattern, sort, ofs); } -static char *repolink(char *title, char *class, char *page, char *head, - char *path) +static char *repolink(const char *title, const char *class, const char *page, + const char *head, const char *path) { char *delim = "?"; @@ -135,175 +207,391 @@ static char *repolink(char *title, char *class, char *page, char *head, html("'"); } html(" href='"); - if (cgit_virtual_root) { - html_attr(cgit_virtual_root); - if (cgit_virtual_root[strlen(cgit_virtual_root) - 1] != '/') - html("/"); - html_attr(cgit_repo->url); - if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') + if (ctx.cfg.virtual_root) { + html_url_path(ctx.cfg.virtual_root); + html_url_path(ctx.repo->url); + if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') html("/"); if (page) { - html(page); + html_url_path(page); html("/"); if (path) - html_attr(path); + html_url_path(path); } } else { - html(cgit_script_name); + html_url_path(ctx.cfg.script_name); html("?url="); - html_attr(cgit_repo->url); - if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') + html_url_arg(ctx.repo->url); + if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') html("/"); if (page) { - html(page); + html_url_arg(page); html("/"); if (path) - html_attr(path); + html_url_arg(path); } delim = "&"; } - if (head && strcmp(head, cgit_repo->defbranch)) { + if (head && strcmp(head, ctx.repo->defbranch)) { html(delim); html("h="); - html_attr(head); + html_url_arg(head); delim = "&"; } return fmt("%s", delim); } -static void reporevlink(char *page, char *name, char *title, char *class, - char *head, char *rev, char *path) +static void reporevlink(const char *page, const char *name, const char *title, + const char *class, const char *head, const char *rev, + const char *path) { char *delim; delim = repolink(title, class, page, head, path); - if (rev && strcmp(rev, cgit_query_head)) { + if (rev && ctx.qry.head != NULL && strcmp(rev, ctx.qry.head)) { html(delim); html("id="); - html_attr(rev); + html_url_arg(rev); } html("'>"); html_txt(name); html(""); } -void cgit_tree_link(char *name, char *title, char *class, char *head, - char *rev, char *path) +void cgit_summary_link(const char *name, const char *title, const char *class, + const char *head) +{ + reporevlink(NULL, name, title, class, head, NULL, NULL); +} + +void cgit_tag_link(const char *name, const char *title, const char *class, + const char *head, const char *rev) +{ + reporevlink("tag", name, title, class, head, rev, NULL); +} + +void cgit_tree_link(const char *name, const char *title, const char *class, + const char *head, const char *rev, const 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) +void cgit_plain_link(const char *name, const char *title, const char *class, + const char *head, const char *rev, const char *path) +{ + reporevlink("plain", name, title, class, head, rev, path); +} + +void cgit_log_link(const char *name, const char *title, const char *class, + const char *head, const char *rev, const char *path, + int ofs, const char *grep, const char *pattern, int showmsg) { char *delim; delim = repolink(title, class, "log", head, path); - if (rev && strcmp(rev, cgit_query_head)) { + if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) { html(delim); html("id="); - html_attr(rev); - delim = "&"; + html_url_arg(rev); + delim = "&"; + } + if (grep && pattern) { + html(delim); + html("qt="); + html_url_arg(grep); + delim = "&"; + html(delim); + html("q="); + html_url_arg(pattern); } if (ofs > 0) { html(delim); html("ofs="); htmlf("%d", ofs); + delim = "&"; + } + if (showmsg) { + html(delim); + html("showmsg=1"); } html("'>"); html_txt(name); html(""); } -void cgit_commit_link(char *name, char *title, char *class, char *head, - char *rev) +void cgit_commit_link(char *name, const char *title, const char *class, + const char *head, const char *rev, const char *path, + int toggle_ssdiff) { - if (strlen(name) > cgit_max_msg_len && cgit_max_msg_len >= 15) { - name[cgit_max_msg_len] = '\0'; - name[cgit_max_msg_len - 1] = '.'; - name[cgit_max_msg_len - 2] = '.'; - name[cgit_max_msg_len - 3] = '.'; + 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] = '.'; + } + + char *delim; + + delim = repolink(title, class, "commit", head, path); + if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) { + html(delim); + html("id="); + html_url_arg(rev); + delim = "&"; + } + if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) { + html(delim); + html("ss=1"); + delim = "&"; + } + if (ctx.qry.context > 0 && ctx.qry.context != 3) { + html(delim); + html("context="); + htmlf("%d", ctx.qry.context); + delim = "&"; } - reporevlink("commit", name, title, class, head, rev, NULL); + if (ctx.qry.ignorews) { + html(delim); + html("ignorews=1"); + delim = "&"; + } + html("'>"); + if (name[0] != '\0') + html_txt(name); + else + html_txt("(no commit message)"); + html(""); } -void cgit_refs_link(char *name, char *title, char *class, char *head, - char *rev, char *path) +void cgit_refs_link(const char *name, const char *title, const char *class, + const char *head, const char *rev, const 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) +void cgit_snapshot_link(const char *name, const char *title, const char *class, + const char *head, const char *rev, + const 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) +void cgit_diff_link(const char *name, const char *title, const char *class, + const char *head, const char *new_rev, const char *old_rev, + const char *path, int toggle_ssdiff) { char *delim; delim = repolink(title, class, "diff", head, path); - if (new_rev && strcmp(new_rev, cgit_query_head)) { + if (new_rev && ctx.qry.head != NULL && strcmp(new_rev, ctx.qry.head)) { html(delim); html("id="); - html_attr(new_rev); + html_url_arg(new_rev); delim = "&"; } if (old_rev) { html(delim); html("id2="); - html_attr(old_rev); + html_url_arg(old_rev); + delim = "&"; + } + if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) { + html(delim); + html("ss=1"); + delim = "&"; + } + if (ctx.qry.context > 0 && ctx.qry.context != 3) { + html(delim); + html("context="); + htmlf("%d", ctx.qry.context); + delim = "&"; + } + if (ctx.qry.ignorews) { + html(delim); + html("ignorews=1"); + delim = "&"; } html("'>"); html_txt(name); html(""); } +void cgit_patch_link(const char *name, const char *title, const char *class, + const char *head, const char *rev, const char *path) +{ + reporevlink("patch", name, title, class, head, rev, path); +} + +void cgit_stats_link(const char *name, const char *title, const char *class, + const char *head, const char *path) +{ + reporevlink("stats", name, title, class, head, NULL, path); +} + +static void cgit_self_link(char *name, const char *title, const char *class, + struct cgit_context *ctx) +{ + if (!strcmp(ctx->qry.page, "repolist")) + cgit_index_link(name, title, class, ctx->qry.search, ctx->qry.sort, + ctx->qry.ofs); + else if (!strcmp(ctx->qry.page, "summary")) + cgit_summary_link(name, title, class, ctx->qry.head); + else if (!strcmp(ctx->qry.page, "tag")) + cgit_tag_link(name, title, class, ctx->qry.head, + ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL); + else if (!strcmp(ctx->qry.page, "tree")) + cgit_tree_link(name, title, class, ctx->qry.head, + ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, + ctx->qry.path); + else if (!strcmp(ctx->qry.page, "plain")) + cgit_plain_link(name, title, class, ctx->qry.head, + ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, + ctx->qry.path); + else if (!strcmp(ctx->qry.page, "log")) + cgit_log_link(name, title, class, ctx->qry.head, + ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, + ctx->qry.path, ctx->qry.ofs, + ctx->qry.grep, ctx->qry.search, + ctx->qry.showmsg); + else if (!strcmp(ctx->qry.page, "commit")) + cgit_commit_link(name, title, class, ctx->qry.head, + ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, + ctx->qry.path, 0); + else if (!strcmp(ctx->qry.page, "patch")) + cgit_patch_link(name, title, class, ctx->qry.head, + ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, + ctx->qry.path); + else if (!strcmp(ctx->qry.page, "refs")) + cgit_refs_link(name, title, class, ctx->qry.head, + ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, + ctx->qry.path); + else if (!strcmp(ctx->qry.page, "snapshot")) + cgit_snapshot_link(name, title, class, ctx->qry.head, + ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, + ctx->qry.path); + else if (!strcmp(ctx->qry.page, "diff")) + cgit_diff_link(name, title, class, ctx->qry.head, + ctx->qry.sha1, ctx->qry.sha2, + ctx->qry.path, 0); + else if (!strcmp(ctx->qry.page, "stats")) + cgit_stats_link(name, title, class, ctx->qry.head, + ctx->qry.path); + else { + /* Don't known how to make link for this page */ + repolink(title, class, ctx->qry.page, ctx->qry.head, ctx->qry.path); + html(">"); + html_txt(name); + html(""); + } +} + void cgit_object_link(struct object *obj) { - char *page, *arg, *url; + char *page, *shortrev, *fullrev, *name; + fullrev = sha1_to_hex(obj->sha1); + shortrev = xstrdup(fullrev); + shortrev[10] = '\0'; if (obj->type == OBJ_COMMIT) { - cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL, - cgit_query_head, sha1_to_hex(obj->sha1)); + cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, + ctx.qry.head, fullrev, NULL, 0); return; - } else if (obj->type == OBJ_TREE) { + } else if (obj->type == OBJ_TREE) page = "tree"; - arg = "id"; - } else { + else if (obj->type == OBJ_TAG) + page = "tag"; + else page = "blob"; - arg = "id"; + name = fmt("%s %s...", typename(obj->type), shortrev); + reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL); +} + +static struct string_list_item *lookup_path(struct string_list *list, + const char *path) +{ + struct string_list_item *item; + + while (path && path[0]) { + if ((item = string_list_lookup(list, path))) + return item; + if (!(path = strchr(path, '/'))) + break; + path++; } + return NULL; +} - url = cgit_pageurl(cgit_query_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_submodule_link(const char *class, char *path, const char *rev) +{ + struct string_list *list; + struct string_list_item *item; + char tail, *dir; + size_t len; + + len = 0; + tail = 0; + list = &ctx.repo->submodules; + item = lookup_path(list, path); + if (!item) { + len = strlen(path); + tail = path[len - 1]; + if (tail == '/') { + path[len - 1] = 0; + item = lookup_path(list, path); + } + } + html("module_link, dir, rev); + } else { + html("#"); + } + html("'>"); + html_txt(path); + html(""); + html_txtf(" @ %.7s", rev); + if (item && tail) + path[len - 1] = tail; } -void cgit_print_date(time_t secs, char *format) +void cgit_print_date(time_t secs, const char *format, int local_time) { char buf[64]; struct tm *time; - time = gmtime(&secs); + if (!secs) + return; + if (local_time) + time = localtime(&secs); + else + time = gmtime(&secs); strftime(buf, sizeof(buf)-1, format, time); html_txt(buf); } -void cgit_print_age(time_t t, time_t max_relative, char *format) +void cgit_print_age(time_t t, time_t max_relative, const char *format) { time_t now, secs; + if (!t) + return; time(&now); secs = now - t; if (secs > max_relative && max_relative >= 0) { - cgit_print_date(t, format); + cgit_print_date(t, format, ctx.cfg.local_time); return; } @@ -336,104 +624,329 @@ 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->env.no_http && !strcmp(ctx->env.no_http, "1")) + return; + + if (ctx->page.status) + htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg); + 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.size) + htmlf("Content-Length: %zd\n", ctx->page.size); + 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)); + if (ctx->page.etag) + htmlf("ETag: \"%s\"\n", ctx->page.etag); html("\n"); + if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD")) + exit(0); +} + +void cgit_print_docstart(struct cgit_context *ctx) +{ + if (ctx->cfg.embedded) { + if (ctx->cfg.header) + html_include(ctx->cfg.header); + return; + } + + const char *host = cgit_hosturl(); html(cgit_doctype); - html("\n"); + html("\n"); html("\n"); html(""); - html_txt(title); + html_txt(ctx->page.title); html("\n"); htmlf("\n", cgit_version); + if (ctx->cfg.robots && *ctx->cfg.robots) + htmlf("\n", ctx->cfg.robots); html("\n"); + if (ctx->cfg.favicon) { + html("\n"); + } + if (host && ctx->repo && ctx->qry.head) { + struct strbuf sb = STRBUF_INIT; + strbuf_addf(&sb, "h=%s", ctx->qry.head); + + html("\n"); + strbuf_release(&sb); + } + if (ctx->cfg.head_include) + html_include(ctx->cfg.head_include); html("\n"); html("\n"); + if (ctx->cfg.header) + html_include(ctx->cfg.header); } void cgit_print_docend() { - html(""); + html(" \n"); + if (ctx.cfg.embedded) { + html(" \n"); + if (ctx.cfg.footer) + html_include(ctx.cfg.footer); + return; + } + if (ctx.cfg.footer) + html_include(ctx.cfg.footer); + else { + htmlf("\n"); + } + html(" \n"); html("\n\n"); } -void cgit_print_pageheader(char *title, int show_search) +static int print_branch_option(const char *refname, const unsigned char *sha1, + int flags, void *cb_data) { - html(""); - html(""); - html("
"); - if (cgit_query_repo) { - html_txt(cgit_repo->name); - html(" ("); - html_txt(cgit_query_head); - html(") :  "); - reporevlink(NULL, "summary", NULL, NULL, cgit_query_head, - NULL, NULL); - html(" "); - cgit_log_link("log", NULL, NULL, cgit_query_head, - cgit_query_sha1, cgit_query_path, 0); - html(" "); - cgit_tree_link("tree", NULL, NULL, cgit_query_head, - cgit_query_sha1, NULL); - html(" "); - cgit_commit_link("commit", NULL, NULL, cgit_query_head, - cgit_query_sha1); - html(" "); - cgit_diff_link("diff", NULL, NULL, cgit_query_head, - cgit_query_sha1, cgit_query_sha2, - cgit_query_path); + char *name = (char *)refname; + html_option(name, name, ctx.qry.head); + return 0; +} + +void cgit_add_hidden_formfields(int incl_head, int incl_search, + const char *page) +{ + if (!ctx.cfg.virtual_root) { + struct strbuf url = STRBUF_INIT; + + strbuf_addf(&url, "%s/%s", ctx.qry.repo, page); + if (ctx.qry.vpath) + strbuf_addf(&url, "/%s", ctx.qry.vpath); + html_hidden("url", url.buf); + strbuf_release(&url); + } + + if (incl_head && ctx.qry.head && ctx.repo->defbranch && + 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 (ctx.qry.showmsg) + html_hidden("showmsg", "1"); + + if (incl_search) { + if (ctx.qry.grep) + html_hidden("qt", ctx.qry.grep); + if (ctx.qry.search) + html_hidden("q", ctx.qry.search); + } +} + +static const char *hc(struct cgit_context *ctx, const char *page) +{ + return strcmp(ctx->qry.page, page) ? NULL : "active"; +} + +static void cgit_print_path_crumbs(struct cgit_context *ctx, char *path) +{ + char *old_path = ctx->qry.path; + char *p = path, *q, *end = path + strlen(path); + + ctx->qry.path = NULL; + cgit_self_link("root", NULL, NULL, ctx); + ctx->qry.path = p = path; + while (p < end) { + if (!(q = strchr(p, '/'))) + q = end; + *q = '\0'; + html_txt("/"); + cgit_self_link(p, NULL, NULL, ctx); + if (q < end) + *q = '/'; + p = q + 1; + } + ctx->qry.path = old_path; +} + +static void print_header(struct cgit_context *ctx) +{ + char *logo = NULL, *logo_link = NULL; + + html("\n"); + html("\n"); + + if (ctx->repo && ctx->repo->logo && *ctx->repo->logo) + logo = ctx->repo->logo; + else + logo = ctx->cfg.logo; + if (ctx->repo && ctx->repo->logo_link && *ctx->repo->logo_link) + logo_link = ctx->repo->logo_link; + else + logo_link = ctx->cfg.logo_link; + if (logo && *logo) { + html("\n"); + } + + html("\n"); + + html(""); - html("\n"); +} + +void cgit_print_pageheader(struct cgit_context *ctx) +{ + html("
"); + if (!ctx->cfg.noheader) + print_header(ctx); + + html(""); - html("
\n"); + if (ctx->repo) { + cgit_summary_link("summary", NULL, hc(ctx, "summary"), + ctx->qry.head); + cgit_refs_link("refs", NULL, hc(ctx, "refs"), ctx->qry.head, + ctx->qry.sha1, NULL); + cgit_log_link("log", NULL, hc(ctx, "log"), ctx->qry.head, + NULL, ctx->qry.vpath, 0, NULL, NULL, + ctx->qry.showmsg); + cgit_tree_link("tree", NULL, hc(ctx, "tree"), ctx->qry.head, + ctx->qry.sha1, ctx->qry.vpath); + cgit_commit_link("commit", NULL, hc(ctx, "commit"), + ctx->qry.head, ctx->qry.sha1, ctx->qry.vpath, 0); + cgit_diff_link("diff", NULL, hc(ctx, "diff"), ctx->qry.head, + ctx->qry.sha1, ctx->qry.sha2, ctx->qry.vpath, 0); + if (ctx->repo->max_stats) + cgit_stats_link("stats", NULL, hc(ctx, "stats"), + ctx->qry.head, ctx->qry.vpath); + if (ctx->repo->readme.nr) + reporevlink("about", "about", NULL, + hc(ctx, "about"), ctx->qry.head, NULL, + NULL); + html(""); + html("
\n"); + cgit_add_hidden_formfields(1, 0, "log"); + html("\n"); + html("\n"); + html("\n"); + html("
\n"); + } else { + site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, NULL, 0); + if (ctx->cfg.root_readme) + site_link("about", "about", NULL, hc(ctx, "about"), + NULL, NULL, 0); + html("
"); html("
"); - if (!cgit_virtual_root) { - if (cgit_query_repo) - html_hidden("r", cgit_query_repo); - if (cgit_query_page) - html_hidden("p", cgit_query_page); - } - if (cgit_query_head) - html_hidden("h", cgit_query_head); - if (cgit_query_sha1) - html_hidden("id", cgit_query_sha1); - if (cgit_query_sha2) - html_hidden("id2", cgit_query_sha2); - html("
"); - } - html("
"); -} - -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"); + html_attr(cgit_rooturl()); + html("'>\n"); + html("\n"); + html("\n"); + html(""); + } + html("
\n"); + if (ctx->qry.vpath) { + html("
"); + html("path: "); + cgit_print_path_crumbs(ctx, ctx->qry.vpath); + html("
"); + } + html("
"); } -/* vim:set sw=8: */ +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; + struct strbuf filename = STRBUF_INIT; + size_t prefixlen; + unsigned char sha1[20]; + + if (get_sha1(fmt("refs/tags/%s", hex), sha1) == 0 && + (hex[0] == 'v' || hex[0] == 'V') && isdigit(hex[1])) + hex++; + strbuf_addf(&filename, "%s-%s", cgit_repobasename(repo), hex); + prefixlen = filename.len; + for (f = cgit_snapshot_formats; f->suffix; f++) { + if (!(snapshots & f->bit)) + continue; + strbuf_setlen(&filename, prefixlen); + strbuf_addstr(&filename, f->suffix); + cgit_snapshot_link(filename.buf, NULL, NULL, NULL, NULL, + filename.buf); + html("
"); + } + strbuf_release(&filename); +}