/* ui-shared.c: common web output functions * * Copyright (C) 2006-2017 cgit Development Team <cgit@lists.zx2c4.com> * * 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"#include "version.h" static const char cgit_doctype[] ="<!DOCTYPE html>\n"; static char *http_date(time_t t){ static char day[][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static char month[][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; struct tm *tm = gmtime(&t); return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday], tm->tm_mday, month[tm->tm_mon], 1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);} void cgit_print_error(const char *fmt, ...){ va_list ap; va_start(ap, fmt); cgit_vprint_error(fmt, ap); va_end(ap);} void cgit_vprint_error(const char *fmt, va_list ap){ va_list cp; html("<div class='error'>"); va_copy(cp, ap); html_vtxtf(fmt, cp); va_end(cp); html("</div>\n");} const char *cgit_httpscheme(void){ if (ctx.env.https && !strcmp(ctx.env.https, "on")) return "https://"; else return "http://";} char *cgit_hosturl(void){ if (ctx.env.http_host) return xstrdup(ctx.env.http_host); if (!ctx.env.server_name) return NULL; if (!ctx.env.server_port || atoi(ctx.env.server_port) == 80) return xstrdup(ctx.env.server_name); return fmtalloc("%s:%s", ctx.env.server_name, ctx.env.server_port);} char *cgit_currenturl(void){ const char *root = cgit_rooturl(); size_t len = strlen(root); if (!ctx.qry.url) return xstrdup(root); if (len && root[len - 1] == '/') return fmtalloc("%s%s", root, ctx.qry.url); return fmtalloc("%s/%s", root, ctx.qry.url);} const char *cgit_rooturl(void){ if (ctx.cfg.virtual_root) return ctx.cfg.virtual_root; else return ctx.cfg.script_name;} const char *cgit_loginurl(void){ static const char *login_url; if (!login_url) login_url = fmtalloc("%s?p=login", cgit_rooturl()); return login_url;} char *cgit_repourl(const char *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){ 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 { 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, NULL, 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 && starts_with(&rvbuf[p-3], ".git")) { 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;} const char *cgit_snapshot_prefix(const struct cgit_repo *repo){ if (repo->snapshot_prefix) return repo->snapshot_prefix; return cgit_repobasename(repo->url);} static void site_url(const char *page, const char *search, const char *sort, int ofs, int always_root){ char *delim = "?"; if (always_root || page) html_attr(cgit_rooturl()); else { char *currenturl = cgit_currenturl(); html_attr(currenturl); free(currenturl); } 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, int always_root){ html("<a"); if (title) { html(" title='"); html_attr(title); html("'"); } if (class) { html(" class='"); html_attr(class); html("'"); } html(" href='"); site_url(page, search, sort, ofs, always_root); html("'>"); html_txt(name); html("</a>");} void cgit_index_link(const char *name, const char *title, const char *class, const char *pattern, const char *sort, int ofs, int always_root){ site_link(NULL, name, title, class, pattern, sort, ofs, always_root);} static char *repolink(const char *title, const char *class, const char *page, const char *head, const char *path){ char *delim = "?"; html("<a"); if (title) { html(" title='"); html_attr(title); html("'"); } if (class) { html(" class='"); html_attr(class); html("'"); } html(" href='"); 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_url_path(page); html("/"); if (path) html_url_path(path); } } else { html_url_path(ctx.cfg.script_name); html("?url="); html_url_arg(ctx.repo->url); if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') html("/"); if (page) { html_url_arg(page); html("/"); if (path) html_url_arg(path); } delim = "&"; } if (head && ctx.repo->defbranch && strcmp(head, ctx.repo->defbranch)) { html(delim); html("h="); html_url_arg(head); delim = "&"; } return fmt("%s", delim);} 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 && ctx.qry.head != NULL && strcmp(rev, ctx.qry.head)) { html(delim); html("id="); html_url_arg(rev); } html("'>"); html_txt(name); html("</a>");} 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 *tag){ reporevlink("tag", name, title, class, tag, NULL, 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_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_blame_link(const char *name, const char *title, const char *class, const char *head, const char *rev, const char *path){ reporevlink("blame", 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, int follow){ char *delim; delim = repolink(title, class, "log", head, path); if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) { html(delim); html("id="); 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"); delim = "&"; } if (follow) { html(delim); html("follow=1"); } html("'>"); html_txt(name); html("</a>");} void cgit_commit_link(const char *name, const char *title, const char *class, const char *head, const char *rev, const char *path){ 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.difftype) { html(delim); htmlf("dt=%d", ctx.qry.difftype); 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 = "&"; } if (ctx.qry.follow) { html(delim); html("follow=1"); } html("'>"); if (name[0] != '\0') { if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { html_ntxt(name, ctx.cfg.max_msg_len - 3); html("..."); } else html_txt(name); } else html_txt("(no commit message)"); html("</a>");} 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(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(const char *name, const char *title, const char *class, const char *head, const char *new_rev, const char *old_rev, const char *path){ char *delim; delim = repolink(title, class, "diff", head, path); if (new_rev && ctx.qry.head != NULL && strcmp(new_rev, ctx.qry.head)) { html(delim); html("id="); html_url_arg(new_rev); delim = "&"; } if (old_rev) { html(delim); html("id2="); html_url_arg(old_rev); delim = "&"; } if (ctx.qry.difftype) { html(delim); htmlf("dt=%d", ctx.qry.difftype); 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 = "&"; } if (ctx.qry.follow) { html(delim); html("follow=1"); } html("'>"); html_txt(name); html("</a>");} 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){ if (!strcmp(ctx.qry.page, "repolist")) cgit_index_link(name, title, class, ctx.qry.search, ctx.qry.sort, ctx.qry.ofs, 1); 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.has_sha1 ? ctx.qry.sha1 : ctx.qry.head); 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, "blame")) cgit_blame_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"))Lines 1–500 of 1184. Load more
/* ui-shared.c: common web output functions * * Copyright (C) 2006-2017 cgit Development Team <cgit@lists.zx2c4.com> * * 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" #include "version.h" static const char cgit_doctype[] = "<!DOCTYPE html>\n"; static char *http_date(time_t t) { static char day[][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static char month[][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; struct tm *tm = gmtime(&t); return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday], tm->tm_mday, month[tm->tm_mon], 1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec); } void cgit_print_error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); cgit_vprint_error(fmt, ap); va_end(ap); } void cgit_vprint_error(const char *fmt, va_list ap) { va_list cp; html("<div class='error'>"); va_copy(cp, ap); html_vtxtf(fmt, cp); va_end(cp); html("</div>\n"); } const char *cgit_httpscheme(void) { if (ctx.env.https && !strcmp(ctx.env.https, "on")) return "https://"; else return "http://"; } char *cgit_hosturl(void) { if (ctx.env.http_host) return xstrdup(ctx.env.http_host); if (!ctx.env.server_name) return NULL; if (!ctx.env.server_port || atoi(ctx.env.server_port) == 80) return xstrdup(ctx.env.server_name); return fmtalloc("%s:%s", ctx.env.server_name, ctx.env.server_port); } char *cgit_currenturl(void) { const char *root = cgit_rooturl(); size_t len = strlen(root); if (!ctx.qry.url) return xstrdup(root); if (len && root[len - 1] == '/') return fmtalloc("%s%s", root, ctx.qry.url); return fmtalloc("%s/%s", root, ctx.qry.url); } const char *cgit_rooturl(void) { if (ctx.cfg.virtual_root) return ctx.cfg.virtual_root; else return ctx.cfg.script_name; } const char *cgit_loginurl(void) { static const char *login_url; if (!login_url) login_url = fmtalloc("%s?p=login", cgit_rooturl()); return login_url; } char *cgit_repourl(const char *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) { 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 { 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, NULL, 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 && starts_with(&rvbuf[p-3], ".git")) { 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; } const char *cgit_snapshot_prefix(const struct cgit_repo *repo) { if (repo->snapshot_prefix) return repo->snapshot_prefix; return cgit_repobasename(repo->url); } static void site_url(const char *page, const char *search, const char *sort, int ofs, int always_root) { char *delim = "?"; if (always_root || page) html_attr(cgit_rooturl()); else { char *currenturl = cgit_currenturl(); html_attr(currenturl); free(currenturl); } 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, int always_root) { html("<a"); if (title) { html(" title='"); html_attr(title); html("'"); } if (class) { html(" class='"); html_attr(class); html("'"); } html(" href='"); site_url(page, search, sort, ofs, always_root); html("'>"); html_txt(name); html("</a>"); } void cgit_index_link(const char *name, const char *title, const char *class, const char *pattern, const char *sort, int ofs, int always_root) { site_link(NULL, name, title, class, pattern, sort, ofs, always_root); } static char *repolink(const char *title, const char *class, const char *page, const char *head, const char *path) { char *delim = "?"; html("<a"); if (title) { html(" title='"); html_attr(title); html("'"); } if (class) { html(" class='"); html_attr(class); html("'"); } html(" href='"); 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_url_path(page); html("/"); if (path) html_url_path(path); } } else { html_url_path(ctx.cfg.script_name); html("?url="); html_url_arg(ctx.repo->url); if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') html("/"); if (page) { html_url_arg(page); html("/"); if (path) html_url_arg(path); } delim = "&"; } if (head && ctx.repo->defbranch && strcmp(head, ctx.repo->defbranch)) { html(delim); html("h="); html_url_arg(head); delim = "&"; } return fmt("%s", delim); } 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 && ctx.qry.head != NULL && strcmp(rev, ctx.qry.head)) { html(delim); html("id="); html_url_arg(rev); } html("'>"); html_txt(name); html("</a>"); } 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 *tag) { reporevlink("tag", name, title, class, tag, NULL, 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_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_blame_link(const char *name, const char *title, const char *class, const char *head, const char *rev, const char *path) { reporevlink("blame", 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, int follow) { char *delim; delim = repolink(title, class, "log", head, path); if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) { html(delim); html("id="); 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"); delim = "&"; } if (follow) { html(delim); html("follow=1"); } html("'>"); html_txt(name); html("</a>"); } void cgit_commit_link(const char *name, const char *title, const char *class, const char *head, const char *rev, const char *path) { 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.difftype) { html(delim); htmlf("dt=%d", ctx.qry.difftype); 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 = "&"; } if (ctx.qry.follow) { html(delim); html("follow=1"); } html("'>"); if (name[0] != '\0') { if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { html_ntxt(name, ctx.cfg.max_msg_len - 3); html("..."); } else html_txt(name); } else html_txt("(no commit message)"); html("</a>"); } 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(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(const char *name, const char *title, const char *class, const char *head, const char *new_rev, const char *old_rev, const char *path) { char *delim; delim = repolink(title, class, "diff", head, path); if (new_rev && ctx.qry.head != NULL && strcmp(new_rev, ctx.qry.head)) { html(delim); html("id="); html_url_arg(new_rev); delim = "&"; } if (old_rev) { html(delim); html("id2="); html_url_arg(old_rev); delim = "&"; } if (ctx.qry.difftype) { html(delim); htmlf("dt=%d", ctx.qry.difftype); 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 = "&"; } if (ctx.qry.follow) { html(delim); html("follow=1"); } html("'>"); html_txt(name); html("</a>"); } 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) { if (!strcmp(ctx.qry.page, "repolist")) cgit_index_link(name, title, class, ctx.qry.search, ctx.qry.sort, ctx.qry.ofs, 1); 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.has_sha1 ? ctx.qry.sha1 : ctx.qry.head); 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, "blame")) cgit_blame_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"))