1265 lines · 31.5 KB · C
RawDownload
/* 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) */ #define USE_THE_REPOSITORY_VARIABLE #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_r(&t, &tm);	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(); 	if (!ctx.qry.url)		return xstrdup(root);	if (root[0] && root[strlen(root) - 1] == '/')		return fmtalloc("%s%s", root, ctx.qry.url);	return fmtalloc("%s/%s", root, ctx.qry.url);} char *cgit_currentfullurl(void){	const char *root = cgit_rooturl();	const char *orig_query = ctx.env.query_string ? ctx.env.query_string : "";	size_t len = strlen(orig_query);	char *query = xmalloc(len + 2), *start_url, *ret; 	/* Remove all url=... parts from query string */	memcpy(query + 1, orig_query, len + 1);	query[0] = '?';	start_url = query;	while ((start_url = strstr(start_url, "url=")) != NULL) {		if (start_url[-1] == '?' || start_url[-1] == '&') {			const char *end_url = strchr(start_url, '&');			if (end_url)				memmove(start_url, end_url + 1, strlen(end_url));			else				start_url[0] = '\0';		} else			++start_url;	}	if (!query[1])		query[0] = '\0'; 	if (!ctx.qry.url)		ret = fmtalloc("%s%s", root, query);	else if (root[0] && root[strlen(root) - 1] == '/')		ret = fmtalloc("%s%s%s", root, ctx.qry.url, query);	else		ret = fmtalloc("%s/%s%s", root, ctx.qry.url, query);	free(query);	return ret;} 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 = "&amp;";	}	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;	size_t len; 	len = strlcpy(rvbuf, reponame, sizeof(rvbuf));	if (len >= sizeof(rvbuf))		die("cgit_repobasename: truncated repository name '%s'", reponame);	p = len - 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 = "&amp;";	}	if (search) {		html(delim);		html("q=");		html_attr(search);		delim = "&amp;";	}	if (sort) {		html(delim);		html("s=");		html_attr(sort);		delim = "&amp;";	}	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 = "&amp;";	}	if (head && ctx.repo->defbranch && strcmp(head, ctx.repo->defbranch)) {		html(delim);		html("h=");		html_url_arg(head);		delim = "&amp;";	}	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 = "&amp;";	}	if (grep && pattern) {		html(delim);		html("qt=");		html_url_arg(grep);		delim = "&amp;";		html(delim);		html("q=");		html_url_arg(pattern);	}	if (ofs > 0) {		html(delim);		html("ofs=");		htmlf("%d", ofs);		delim = "&amp;";	}	if (showmsg) {		html(delim);		html("showmsg=1");		delim = "&amp;";	}	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 = "&amp;";	}	if (ctx.qry.difftype) {		html(delim);		htmlf("dt=%d", ctx.qry.difftype);		delim = "&amp;";	}	if (ctx.qry.context > 0 && ctx.qry.context != 3) {		html(delim);		html("context=");		htmlf("%d", ctx.qry.context);		delim = "&amp;";	}	if (ctx.qry.ignorews) {		html(delim);		html("ignorews=1");		delim = "&amp;";	}	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 = "&amp;";	}	if (old_rev) {		html(delim);		html("id2=");		html_url_arg(old_rev);		delim = "&amp;";	}	if (ctx.qry.difftype) {		html(delim);		htmlf("dt=%d", ctx.qry.difftype);		delim = "&amp;";	}	if (ctx.qry.context > 0 && ctx.qry.context != 3) {		html(delim);		html("context=");		htmlf("%d", ctx.qry.context);		delim = "&amp;";	}	if (ctx.qry.ignorews) {		html(delim);		html("ignorews=1");		delim = "&amp;";	}	if (ctx.qry.follow) {		html(delim);		html("follow=1");

Lines 1–500 of 1265.