aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlookshe <github@lookshe.org>2016-07-12 09:22:30 +0200
committerlookshe <github@lookshe.org>2016-07-12 09:22:30 +0200
commit1787404b6a618d07200db241c004d1bedc92f874 (patch)
treeaff8c654e8f3190210f80b4c886ee5a8e88e26fd
parent2209fe5157b431cf57898deb889acdcc704dda64 (diff)
parent40fbefba0514b33988d453aea05aa2b956e98f84 (diff)
Merge branch 'master' into lookshe/masterlookshe/master
Conflicts: filters/html-converters/md2html
-rw-r--r--Makefile4
-rw-r--r--README4
-rw-r--r--cgit.c6
-rw-r--r--cgit.css29
-rw-r--r--cgit.h11
-rw-r--r--cgit.mk12
-rw-r--r--cgitrc.5.txt19
-rw-r--r--cmd.c14
-rw-r--r--filters/gentoo-ldap-authentication.lua2
m---------git0
-rw-r--r--parsing.c10
-rw-r--r--scan-tree.c4
-rw-r--r--shared.c1
-rw-r--r--ui-atom.c6
-rw-r--r--ui-commit.c6
-rw-r--r--ui-diff.c2
-rw-r--r--ui-log.c55
-rw-r--r--ui-plain.c2
-rw-r--r--ui-refs.c30
-rw-r--r--ui-repolist.c2
-rw-r--r--ui-shared.c97
-rw-r--r--ui-shared.h6
-rw-r--r--ui-stats.c21
-rw-r--r--ui-tag.c3
24 files changed, 196 insertions, 150 deletions
diff --git a/Makefile b/Makefile
index 6590d8e..c7a57f8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
all::
-CGIT_VERSION = v0.12
+CGIT_VERSION = v1.0
CGIT_SCRIPT_NAME = cgit.cgi
CGIT_SCRIPT_PATH = /var/www/htdocs/cgit
CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH)
@@ -14,7 +14,7 @@ htmldir = $(docdir)
pdfdir = $(docdir)
mandir = $(prefix)/share/man
SHA1_HEADER = <openssl/sha.h>
-GIT_VER = 2.7.0
+GIT_VER = 2.9.0
GIT_URL = https://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.gz
INSTALL = install
COPYTREE = cp -r
diff --git a/README b/README
index 917d74a..7a6b4a4 100644
--- a/README
+++ b/README
@@ -92,8 +92,8 @@ the HTTP headers `Modified` and `Expires`.
Online presence
---------------
-* The cgit homepage is hosted by cgit at <http://git.zx2c4.com/cgit/about/>
+* The cgit homepage is hosted by cgit at <https://git.zx2c4.com/cgit/about/>
* Patches, bug reports, discussions and support should go to the cgit
mailing list: <cgit@lists.zx2c4.com>. To sign up, visit
- <http://lists.zx2c4.com/mailman/listinfo/cgit>
+ <https://lists.zx2c4.com/mailman/listinfo/cgit>
diff --git a/cgit.c b/cgit.c
index 62e5e28..98df32d 100644
--- a/cgit.c
+++ b/cgit.c
@@ -41,6 +41,8 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va
repo->desc = xstrdup(value);
else if (!strcmp(name, "owner"))
repo->owner = xstrdup(value);
+ else if (!strcmp(name, "homepage"))
+ repo->homepage = xstrdup(value);
else if (!strcmp(name, "defbranch"))
repo->defbranch = xstrdup(value);
else if (!strcmp(name, "snapshots"))
@@ -795,6 +797,8 @@ static void print_repo(FILE *f, struct cgit_repo *repo)
fprintf(f, "repo.module-link=%s\n", repo->module_link);
if (repo->section)
fprintf(f, "repo.section=%s\n", repo->section);
+ if (repo->homepage)
+ fprintf(f, "repo.homepage=%s\n", repo->homepage);
if (repo->clone_url)
fprintf(f, "repo.clone-url=%s\n", repo->clone_url);
fprintf(f, "repo.enable-commit-graph=%d\n",
@@ -939,7 +943,7 @@ static void cgit_parse_args(int argc, const char **argv)
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--version")) {
- printf("CGit %s | http://git.zx2c4.com/cgit/\n\nCompiled in features:\n", CGIT_VERSION);
+ printf("CGit %s | https://git.zx2c4.com/cgit/\n\nCompiled in features:\n", CGIT_VERSION);
#ifdef NO_LUA
printf("[-] ");
#else
diff --git a/cgit.css b/cgit.css
index 555dd7c..159e062 100644
--- a/cgit.css
+++ b/cgit.css
@@ -18,7 +18,7 @@ div#cgit a:hover {
}
div#cgit table {
- border-collapse: collapse;
+ border-collapse: collapse;
}
div#cgit table#header {
@@ -85,6 +85,12 @@ div#cgit table.tabs td a.active {
background-color: #ccc;
}
+div#cgit table.tabs a[href^="http://"]:after, div#cgit table.tabs a[href^="https://"]:after {
+ content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhcJDQY+gm2TAAAAHWlUWHRDb21tZW50AAAAAABDcmVhdGVkIHdpdGggR0lNUGQuZQcAAABbSURBVAhbY2BABs4MU4CwhYHBh2Erww4wrGFQZHjI8B8IgUIscJWyDHcggltQhI4zGDCcRwhChPggHIggP1QoAVmQkSETrGoHsiAEsACtBYN0oDAMbgU6EBcAAL2eHUt4XUU4AAAAAElFTkSuQmCC);
+ opacity: 0.5;
+ margin: 0 0 0 5px;
+}
+
div#cgit table.tabs td.form {
text-align: right;
}
@@ -588,19 +594,31 @@ div#cgit span.age-months {
div#cgit span.age-years {
color: #bbb;
}
+
+div#cgit span.insertions {
+ color: #080;
+}
+
+div#cgit span.deletions {
+ color: #800;
+}
+
div#cgit div.footer {
margin-top: 0.5em;
text-align: center;
font-size: 80%;
color: #ccc;
}
+
div#cgit div.footer a {
color: #ccc;
text-decoration: none;
}
+
div#cgit div.footer a:hover {
text-decoration: underline;
}
+
div#cgit a.branch-deco {
color: #000;
margin: 0px 0.5em;
@@ -608,6 +626,7 @@ div#cgit a.branch-deco {
background-color: #88ff88;
border: solid 1px #007700;
}
+
div#cgit a.tag-deco {
color: #000;
margin: 0px 0.5em;
@@ -615,6 +634,7 @@ div#cgit a.tag-deco {
background-color: #ffff88;
border: solid 1px #777700;
}
+
div#cgit a.remote-deco {
color: #000;
margin: 0px 0.5em;
@@ -622,6 +642,7 @@ div#cgit a.remote-deco {
background-color: #ccccff;
border: solid 1px #000077;
}
+
div#cgit a.deco {
color: #000;
margin: 0px 0.5em;
@@ -801,9 +822,9 @@ div#cgit table.ssdiff td.head div.head {
div#cgit table.ssdiff td.foot {
border-top: solid 1px #aaa;
- border-left: none;
- border-right: none;
- border-bottom: none;
+ border-left: none;
+ border-right: none;
+ border-bottom: none;
}
div#cgit table.ssdiff td.space {
diff --git a/cgit.h b/cgit.h
index 567bfec..a5ac954 100644
--- a/cgit.h
+++ b/cgit.h
@@ -29,13 +29,6 @@
#undef isgraph
#define isgraph(x) (isprint((x)) && !isspace((x)))
-/*
- * Dateformats used on misc. pages
- */
-#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S (%Z)"
-#define FMT_SHORTDATE "%Y-%m-%d"
-#define FMT_ATOMDATE "%Y-%m-%dT%H:%M:%SZ"
-
/*
* Limits used for relative dates
@@ -88,6 +81,7 @@ struct cgit_repo {
char *path;
char *desc;
char *owner;
+ char *homepage;
char *defbranch;
char *module_link;
struct string_list readme;
@@ -130,9 +124,11 @@ struct commitinfo {
char *author;
char *author_email;
unsigned long author_date;
+ int author_tz;
char *committer;
char *committer_email;
unsigned long committer_date;
+ int committer_tz;
char *subject;
char *msg;
char *msg_encoding;
@@ -142,6 +138,7 @@ struct taginfo {
char *tagger;
char *tagger_email;
unsigned long tagger_date;
+ int tagger_tz;
char *msg;
};
diff --git a/cgit.mk b/cgit.mk
index 1b50307..8d4f5e0 100644
--- a/cgit.mk
+++ b/cgit.mk
@@ -21,6 +21,8 @@ CGIT_CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"'
CGIT_CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"'
CGIT_CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"'
+PKG_CONFIG ?= pkg-config
+
ifdef NO_C99_FORMAT
CFLAGS += -DNO_C99_FORMAT
endif
@@ -31,7 +33,7 @@ ifdef NO_LUA
else
ifeq ($(LUA_PKGCONFIG),)
LUA_PKGCONFIG := $(shell for pc in luajit lua lua5.2 lua5.1; do \
- pkg-config --exists $$pc 2>/dev/null && echo $$pc && break; \
+ $(PKG_CONFIG) --exists $$pc 2>/dev/null && echo $$pc && break; \
done)
LUA_MODE := autodetected
else
@@ -39,8 +41,8 @@ else
endif
ifneq ($(LUA_PKGCONFIG),)
LUA_MESSAGE := linking with $(LUA_MODE) $(LUA_PKGCONFIG)
- LUA_LIBS := $(shell pkg-config --libs $(LUA_PKGCONFIG) 2>/dev/null)
- LUA_CFLAGS := $(shell pkg-config --cflags $(LUA_PKGCONFIG) 2>/dev/null)
+ LUA_LIBS := $(shell $(PKG_CONFIG) --libs $(LUA_PKGCONFIG) 2>/dev/null)
+ LUA_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(LUA_PKGCONFIG) 2>/dev/null)
CGIT_LIBS += $(LUA_LIBS)
CGIT_CFLAGS += $(LUA_CFLAGS)
else
@@ -51,8 +53,8 @@ endif
endif
-# Add -ldl to linker flags on non-BSD systems.
-ifeq ($(findstring BSD,$(uname_S)),)
+# Add -ldl to linker flags on systems that commonly use GNU libc.
+ifneq (,$(filter $(uname_S),Linux GNU/kFreeBSD))
CGIT_LIBS += -ldl
endif
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 47850a8..9fcf445 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -205,11 +205,11 @@ enable-git-config::
Flag which, when set to "1", will allow cgit to use git config to set
any repo specific settings. This option is used in conjunction with
"scan-path", and must be defined prior, to augment repo-specific
- settings. The keys gitweb.owner, gitweb.category, and gitweb.description
- will map to the cgit keys repo.owner, repo.section, and repo.desc,
- respectively. All git config keys that begin with "cgit." will be mapped
- to the corresponding "repo." key in cgit. Default value: "0". See also:
- scan-path, section-from-path.
+ settings. The keys gitweb.owner, gitweb.category, gitweb.description,
+ and gitweb.homepage will map to the cgit keys repo.owner, repo.section,
+ repo.desc, and repo.homepage respectively. All git config keys that begin
+ with "cgit." will be mapped to the corresponding "repo." key in cgit.
+ Default value: "0". See also: scan-path, section-from-path.
favicon::
Url used as link to a shortcut icon for cgit. It is suggested to use
@@ -496,6 +496,9 @@ repo.defbranch::
repo.desc::
The value to show as repository description. Default value: none.
+repo.homepage::
+ The value to show as repository homepage. Default value: none.
+
repo.email-filter::
Override the default email-filter. Default value: none. See also:
"enable-filter-overrides". See also: "FILTER API".
@@ -520,7 +523,7 @@ repo.enable-subject-links::
A flag which can be used to override the global setting
`enable-subject-links'. Default value: none.
-enable-html-serving::
+repo.enable-html-serving::
A flag which can be used to override the global setting
`enable-html-serving`. Default value: none.
@@ -673,14 +676,14 @@ commit filter::
expected on standard output.
email filter::
- This filter is given two parameters: the email address of the relevent
+ This filter is given two parameters: the email address of the relevant
author and a string indicating the originating page. The filter will
then receive the text string to format on standard input and is
expected to write to standard output the formatted text to be included
in the page.
owner filter::
- This filter is given no arguments. The owner text is avilable on
+ This filter is given no arguments. The owner text is available on
standard input and the filter is expected to write to standard
output. The output is included in the Owner column.
diff --git a/cmd.c b/cmd.c
index 3093c62..d280e95 100644
--- a/cmd.c
+++ b/cmd.c
@@ -39,16 +39,26 @@ static void atom_fn(void)
static void about_fn(void)
{
if (ctx.repo) {
+ size_t path_info_len = ctx.env.path_info ? strlen(ctx.env.path_info) : 0;
if (!ctx.qry.path &&
ctx.qry.url[strlen(ctx.qry.url) - 1] != '/' &&
- ctx.env.path_info[strlen(ctx.env.path_info) - 1] != '/') {
+ (!path_info_len || ctx.env.path_info[path_info_len - 1] != '/')) {
char *currenturl = cgit_currenturl();
char *redirect = fmtalloc("%s/", currenturl);
cgit_redirect(redirect, true);
free(currenturl);
free(redirect);
- } else
+ } else if (ctx.repo->readme.nr)
cgit_print_repo_readme(ctx.qry.path);
+ else if (ctx.repo->homepage)
+ cgit_redirect(ctx.repo->homepage, false);
+ else {
+ char *currenturl = cgit_currenturl();
+ char *redirect = fmtalloc("%s../", currenturl);
+ cgit_redirect(redirect, false);
+ free(currenturl);
+ free(redirect);
+ }
} else
cgit_print_site_readme();
}
diff --git a/filters/gentoo-ldap-authentication.lua b/filters/gentoo-ldap-authentication.lua
index fce5632..6d8eb3e 100644
--- a/filters/gentoo-ldap-authentication.lua
+++ b/filters/gentoo-ldap-authentication.lua
@@ -4,7 +4,7 @@
-- luacrypto >= 0.3
-- <http://mkottman.github.io/luacrypto/>
-- lualdap >= 1.2
--- <http://git.zx2c4.com/lualdap/about/>
+-- <https://git.zx2c4.com/lualdap/about/>
--
diff --git a/git b/git
-Subproject 754884255bb580df159e58defa81cdd30b5c430
+Subproject 05219a1276341e72d8082d76b7f5ed394b7437a
diff --git a/parsing.c b/parsing.c
index 5283e58..9dacb16 100644
--- a/parsing.c
+++ b/parsing.c
@@ -69,7 +69,7 @@ static char *substr(const char *head, const char *tail)
return buf;
}
-static void parse_user(const char *t, char **name, char **email, unsigned long *date)
+static void parse_user(const char *t, char **name, char **email, unsigned long *date, int *tz)
{
struct ident_split ident;
unsigned email_len;
@@ -83,6 +83,8 @@ static void parse_user(const char *t, char **name, char **email, unsigned long *
if (ident.date_begin)
*date = strtoul(ident.date_begin, NULL, 10);
+ if (ident.tz_begin)
+ *tz = atoi(ident.tz_begin);
}
}
@@ -147,13 +149,13 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
if (p && skip_prefix(p, "author ", &p)) {
parse_user(p, &ret->author, &ret->author_email,
- &ret->author_date);
+ &ret->author_date, &ret->author_tz);
p = next_header_line(p);
}
if (p && skip_prefix(p, "committer ", &p)) {
parse_user(p, &ret->committer, &ret->committer_email,
- &ret->committer_date);
+ &ret->committer_date, &ret->committer_tz);
p = next_header_line(p);
}
@@ -208,7 +210,7 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
for (p = data; !end_of_header(p); p = next_header_line(p)) {
if (skip_prefix(p, "tagger ", &p)) {
parse_user(p, &ret->tagger, &ret->tagger_email,
- &ret->tagger_date);
+ &ret->tagger_date, &ret->tagger_tz);
}
}
diff --git a/scan-tree.c b/scan-tree.c
index b5a10ff..1cb4e5d 100644
--- a/scan-tree.c
+++ b/scan-tree.c
@@ -61,6 +61,8 @@ static int gitconfig_config(const char *key, const char *value, void *cb)
config_fn(repo, "desc", value);
else if (!strcmp(key, "gitweb.category"))
config_fn(repo, "section", value);
+ else if (!strcmp(key, "gitweb.homepage"))
+ config_fn(repo, "homepage", value);
else if (starts_with(key, "cgit."))
config_fn(repo, key + 5, value);
@@ -244,7 +246,7 @@ void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn
projectsfile, strerror(errno), errno);
return;
}
- while (strbuf_getline(&line, projects, '\n') != EOF) {
+ while (strbuf_getline(&line, projects) != EOF) {
if (!line.len)
continue;
strbuf_insert(&line, 0, "/", 1);
diff --git a/shared.c b/shared.c
index b65e801..e535839 100644
--- a/shared.c
+++ b/shared.c
@@ -54,6 +54,7 @@ struct cgit_repo *cgit_add_repo(const char *url)
ret->path = NULL;
ret->desc = cgit_default_repo_desc;
ret->owner = NULL;
+ ret->homepage = NULL;
ret->section = ctx.cfg.section;
ret->snapshots = ctx.cfg.snapshots;
ret->enable_commit_graph = ctx.cfg.enable_commit_graph;
diff --git a/ui-atom.c b/ui-atom.c
index 11ea0c0..41838d3 100644
--- a/ui-atom.c
+++ b/ui-atom.c
@@ -25,7 +25,8 @@ static void add_entry(struct commit *commit, const char *host)
html_txt(info->subject);
html("</title>\n");
html("<updated>");
- cgit_print_date(info->committer_date, FMT_ATOMDATE, 0);
+ html_txt(show_date(info->committer_date, 0,
+ date_mode_from_type(DATE_ISO8601_STRICT)));
html("</updated>\n");
html("<author>\n");
if (info->author) {
@@ -50,7 +51,8 @@ static void add_entry(struct commit *commit, const char *host)
}
html("</author>\n");
html("<published>");
- cgit_print_date(info->author_date, FMT_ATOMDATE, 0);
+ html_txt(show_date(info->author_date, 0,
+ date_mode_from_type(DATE_ISO8601_STRICT)));
html("</published>\n");
if (host) {
char *pageurl;
diff --git a/ui-commit.c b/ui-commit.c
index d3f7922..e0b4297 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -55,7 +55,8 @@ void cgit_print_commit(char *hex, const char *prefix)
}
cgit_close_filter(ctx.repo->email_filter);
html("</td><td class='right'>");
- cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time);
+ html_txt(show_date(info->author_date, info->author_tz,
+ cgit_date_mode(DATE_ISO8601)));
html("</td></tr>\n");
html("<tr><th>committer</th><td>");
cgit_open_filter(ctx.repo->email_filter, info->committer_email, "commit");
@@ -66,7 +67,8 @@ void cgit_print_commit(char *hex, const char *prefix)
}
cgit_close_filter(ctx.repo->email_filter);
html("</td><td class='right'>");
- cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time);
+ html_txt(show_date(info->committer_date, info->committer_tz,
+ cgit_date_mode(DATE_ISO8601)));
html("</td></tr>\n");
html("<tr><th>commit</th><td colspan='2' class='sha1'>");
tmp = oid_to_hex(&commit->object.oid);
diff --git a/ui-diff.c b/ui-diff.c
index 52ed942..edee793 100644
--- a/ui-diff.c
+++ b/ui-diff.c
@@ -340,7 +340,7 @@ void cgit_print_diff_ctrls(void)
html("<div class='cgit-panel'>");
html("<b>diff options</b>");
- html("<form method='get' action='.'>");
+ html("<form method='get'>");
cgit_add_hidden_formfields(1, 0, ctx.qry.page);
html("<table>");
html("<tr><td colspan='2'/></tr>");
diff --git a/ui-log.c b/ui-log.c
index 4cb93b3..f3c5c24 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -61,38 +61,38 @@ void show_commit_decorations(struct commit *commit)
buf[sizeof(buf) - 1] = 0;
deco = get_name_decoration(&commit->object);
+ if (!deco)
+ return;
html("<span class='decoration'>");
while (deco) {
- if (starts_with(deco->name, "refs/heads/")) {
- strncpy(buf, deco->name + 11, sizeof(buf) - 1);
+ strncpy(buf, prettify_refname(deco->name), sizeof(buf) - 1);
+ switch(deco->type) {
+ case DECORATION_NONE:
+ /* If the git-core doesn't recognize it,
+ * don't display anything. */
+ break;
+ case DECORATION_REF_LOCAL:
cgit_log_link(buf, NULL, "branch-deco", buf, NULL,
- ctx.qry.vpath, 0, NULL, NULL,
- ctx.qry.showmsg, 0);
- }
- else if (starts_with(deco->name, "tag: refs/tags/")) {
- strncpy(buf, deco->name + 15, sizeof(buf) - 1);
- cgit_tag_link(buf, NULL, "tag-deco", buf);
- }
- else if (starts_with(deco->name, "refs/tags/")) {
- strncpy(buf, deco->name + 10, sizeof(buf) - 1);
+ ctx.qry.vpath, 0, NULL, NULL,
+ ctx.qry.showmsg, 0);
+ break;
+ case DECORATION_REF_TAG:
cgit_tag_link(buf, NULL, "tag-deco", buf);
- }
- else if (starts_with(deco->name, "refs/remotes/")) {
+ break;
+ case DECORATION_REF_REMOTE:
if (!ctx.repo->enable_remote_branches)
- goto next;
- strncpy(buf, deco->name + 13, sizeof(buf) - 1);
+ break;
cgit_log_link(buf, NULL, "remote-deco", NULL,
- oid_to_hex(&commit->object.oid),
- ctx.qry.vpath, 0, NULL, NULL,
- ctx.qry.showmsg, 0);
- }
- else {
- strncpy(buf, deco->name, sizeof(buf) - 1);
+ oid_to_hex(&commit->object.oid),
+ ctx.qry.vpath, 0, NULL, NULL,
+ ctx.qry.showmsg, 0);
+ break;
+ default:
cgit_commit_link(buf, NULL, "deco", ctx.qry.head,
- oid_to_hex(&commit->object.oid),
- ctx.qry.vpath);
+ oid_to_hex(&commit->object.oid),
+ ctx.qry.vpath);
+ break;
}
-next:
deco = deco->next;
}
html("</span>");
@@ -204,7 +204,7 @@ static void print_commit(struct commit *commit, struct rev_info *revs)
}
else {
html("<td>");
- cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
+ cgit_print_age(info->committer_date, info->committer_tz, TM_WEEK * 2);
html("</td>");
}
@@ -244,7 +244,7 @@ static void print_commit(struct commit *commit, struct rev_info *revs)
if (revs->graph) {
html("</td><td>");
- cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
+ cgit_print_age(info->committer_date, info->committer_tz, TM_WEEK * 2);
}
if (!lines_counted && (ctx.repo->enable_log_filecount ||
@@ -258,7 +258,8 @@ static void print_commit(struct commit *commit, struct rev_info *revs)
if (ctx.repo->enable_log_filecount)
htmlf("</td><td>%d", files);
if (ctx.repo->enable_log_linecount)
- htmlf("</td><td>-%d/+%d", rem_lines, add_lines);
+ htmlf("</td><td><span class='deletions'>-%d</span>/"
+ "<span class='insertions'>+%d</span>", rem_lines, add_lines);
html("</td></tr>\n");
diff --git a/ui-plain.c b/ui-plain.c
index ff85113..97cf639 100644
--- a/ui-plain.c
+++ b/ui-plain.c
@@ -143,7 +143,7 @@ static int walk_tree(const unsigned char *sha1, struct strbuf *base,
walk_tree_ctx->match = 2;
return READ_TREE_RECURSIVE;
}
- } else if (base->len > walk_tree_ctx->match_baselen) {
+ } else if (base->len < INT_MAX && (int)base->len > walk_tree_ctx->match_baselen) {
print_dir_entry(sha1, base->buf, base->len, pathname, mode);
walk_tree_ctx->match = 2;
} else if (S_ISDIR(mode)) {
diff --git a/ui-refs.c b/ui-refs.c
index d65b060..9018071 100644
--- a/ui-refs.c
+++ b/ui-refs.c
@@ -73,7 +73,7 @@ static int print_branch(struct refinfo *ref)
cgit_author_link(info->author, name);
cgit_close_filter(ctx.repo->email_filter);
html("</td><td colspan='2'>");
- cgit_print_age(info->commit->date, -1, NULL);
+ cgit_print_age(info->committer_date, info->committer_tz, -1);
} else {
html("</td><td></td><td>");
cgit_object_link(ref->object);
@@ -93,34 +93,28 @@ static void print_tag_header(void)
static void print_tag_downloads(const struct cgit_repo *repo, const char *ref)
{
const struct cgit_snapshot_format* f;
- struct strbuf filename = STRBUF_INIT;
const char *basename;
- int free_ref = 0;
+ struct strbuf filename = STRBUF_INIT;
+ size_t prefixlen;
if (!ref || strlen(ref) < 1)
return;
basename = cgit_repobasename(repo->url);
- if (!starts_with(ref, basename)) {
- if ((ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1]))
- ref++;
- if (isdigit(ref[0])) {
- ref = fmtalloc("%s-%s", basename, ref);
- free_ref = 1;
- }
- }
-
+ if (starts_with(ref, basename))
+ strbuf_addstr(&filename, ref);
+ else
+ cgit_compose_snapshot_prefix(&filename, basename, ref);
+ prefixlen = filename.len;
for (f = cgit_snapshot_formats; f->suffix; f++) {
if (!(repo->snapshots & f->bit))
continue;
- strbuf_reset(&filename);
- strbuf_addf(&filename, "%s%s", ref, f->suffix);
+ strbuf_setlen(&filename, prefixlen);
+ strbuf_addstr(&filename, f->suffix);
cgit_snapshot_link(filename.buf, NULL, NULL, NULL, NULL, filename.buf);
html("&nbsp;&nbsp;");
}
- if (free_ref)
- free((char *)ref);
strbuf_release(&filename);
}
@@ -161,9 +155,9 @@ static int print_tag(struct refinfo *ref)
html("</td><td colspan='2'>");
if (info) {
if (info->tagger_date > 0)
- cgit_print_age(info->tagger_date, -1, NULL);
+ cgit_print_age(info->tagger_date, info->tagger_tz, -1);
} else if (ref->object->type == OBJ_COMMIT) {
- cgit_print_age(ref->commit->commit->date, -1, NULL);
+ cgit_print_age(ref->commit->commit->date, 0, -1);
}
html("</td></tr>\n");
diff --git a/ui-repolist.c b/ui-repolist.c
index 6010a39..30915df 100644
--- a/ui-repolist.c
+++ b/ui-repolist.c
@@ -79,7 +79,7 @@ static void print_modtime(struct cgit_repo *repo)
{
time_t t;
if (get_repo_modtime(repo, &t))
- cgit_print_age(t, -1, NULL);
+ cgit_print_age(t, 0, -1);
}
static int is_match(struct cgit_repo *repo)
diff --git a/ui-shared.c b/ui-shared.c
index d978524..05b613e 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -12,8 +12,7 @@
#include "html.h"
static const char cgit_doctype[] =
-"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
-" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
+"<!DOCTYPE html>\n";
static char *http_date(time_t t)
{
@@ -254,7 +253,7 @@ static char *repolink(const char *title, const char *class, const char *page,
}
delim = "&amp;";
}
- if (head && strcmp(head, ctx.repo->defbranch)) {
+ if (head && ctx.repo->defbranch && strcmp(head, ctx.repo->defbranch)) {
html(delim);
html("h=");
html_url_arg(head);
@@ -655,35 +654,23 @@ void cgit_submodule_link(const char *class, char *path, const char *rev)
path[len - 1] = tail;
}
-static const char *fmt_date(time_t secs, const char *format, int local_time)
+const struct date_mode *cgit_date_mode(enum date_mode_type type)
{
- static char buf[64];
- struct tm *time;
-
- if (!secs)
- return "";
- if (local_time)
- time = localtime(&secs);
- else
- time = gmtime(&secs);
- strftime(buf, sizeof(buf)-1, format, time);
- return buf;
-}
-
-void cgit_print_date(time_t secs, const char *format, int local_time)
-{
- html_txt(fmt_date(secs, format, local_time));
+ static struct date_mode mode;
+ mode.type = type;
+ mode.local = ctx.cfg.local_time;
+ return &mode;
}
-static void print_rel_date(time_t t, double value,
+static void print_rel_date(time_t t, int tz, double value,
const char *class, const char *suffix)
{
htmlf("<span class='%s' title='", class);
- html_attr(fmt_date(t, FMT_LONGDATE, ctx.cfg.local_time));
+ html_attr(show_date(t, tz, cgit_date_mode(DATE_ISO8601)));
htmlf("'>%.0f %s</span>", value, suffix);
}
-void cgit_print_age(time_t t, time_t max_relative, const char *format)
+void cgit_print_age(time_t t, int tz, time_t max_relative)
{
time_t now, secs;
@@ -696,34 +683,34 @@ void cgit_print_age(time_t t, time_t max_relative, const char *format)
if (secs > max_relative && max_relative >= 0) {
html("<span title='");
- html_attr(fmt_date(t, FMT_LONGDATE, ctx.cfg.local_time));
+ html_attr(show_date(t, tz, cgit_date_mode(DATE_ISO8601)));
html("'>");
- cgit_print_date(t, format, ctx.cfg.local_time);
+ html_txt(show_date(t, tz, cgit_date_mode(DATE_SHORT)));
html("</span>");
return;
}
if (secs < TM_HOUR * 2) {
- print_rel_date(t, secs * 1.0 / TM_MIN, "age-mins", "min.");
+ print_rel_date(t, tz, secs * 1.0 / TM_MIN, "age-mins", "min.");
return;
}
if (secs < TM_DAY * 2) {
- print_rel_date(t, secs * 1.0 / TM_HOUR, "age-hours", "hours");
+ print_rel_date(t, tz, secs * 1.0 / TM_HOUR, "age-hours", "hours");
return;
}
if (secs < TM_WEEK * 2) {
- print_rel_date(t, secs * 1.0 / TM_DAY, "age-days", "days");
+ print_rel_date(t, tz, secs * 1.0 / TM_DAY, "age-days", "days");
return;
}
if (secs < TM_MONTH * 2) {
- print_rel_date(t, secs * 1.0 / TM_WEEK, "age-weeks", "weeks");
+ print_rel_date(t, tz, secs * 1.0 / TM_WEEK, "age-weeks", "weeks");
return;
}
if (secs < TM_YEAR * 2) {
- print_rel_date(t, secs * 1.0 / TM_MONTH, "age-months", "months");
+ print_rel_date(t, tz, secs * 1.0 / TM_MONTH, "age-months", "months");
return;
}
- print_rel_date(t, secs * 1.0 / TM_YEAR, "age-years", "years");
+ print_rel_date(t, tz, secs * 1.0 / TM_YEAR, "age-years", "years");
}
void cgit_print_http_headers(void)
@@ -762,7 +749,6 @@ void cgit_redirect(const char *url, bool permanent)
html("Location: ");
html_url_path(url);
html("\n\n");
- exit(0);
}
static void print_rel_vcs_link(const char *url)
@@ -784,7 +770,7 @@ void cgit_print_docstart(void)
char *host = cgit_hosturl();
html(cgit_doctype);
- html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n");
+ html("<html lang='en'>\n");
html("<head>\n");
html("<title>");
html_txt(ctx.page.title);
@@ -838,9 +824,9 @@ void cgit_print_docend(void)
if (ctx.cfg.footer)
html_include(ctx.cfg.footer);
else {
- htmlf("<div class='footer'>generated by <a href='http://git.zx2c4.com/cgit/about/'>cgit %s</a> at ",
+ htmlf("<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit %s</a> at ",
cgit_version);
- cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time);
+ html_txt(show_date(time(NULL), 0, cgit_date_mode(DATE_ISO8601)));
html("</div>\n");
}
html("</div> <!-- id=cgit -->\n");
@@ -853,13 +839,11 @@ void cgit_print_error_page(int code, const char *msg, const char *fmt, ...)
ctx.page.expires = ctx.cfg.cache_dynamic_ttl;
ctx.page.status = code;
ctx.page.statusmsg = msg;
- cgit_print_http_headers();
- cgit_print_docstart();
- cgit_print_pageheader();
+ cgit_print_layout_start();
va_start(ap, fmt);
cgit_vprint_error(fmt, ap);
va_end(ap);
- cgit_print_docend();
+ cgit_print_layout_end();
}
void cgit_print_layout_start(void)
@@ -1001,14 +985,14 @@ static void print_header(void)
cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL);
if (ctx.env.authenticated) {
html("</td><td class='form'>");
- html("<form method='get' action=''>\n");
+ html("<form method='get'>\n");
cgit_add_hidden_formfields(0, 1, ctx.qry.page);
html("<select name='h' onchange='this.form.submit();'>\n");
for_each_branch_ref(print_branch_option, ctx.qry.head);
if (ctx.repo->enable_remote_branches)
for_each_remote_ref(print_branch_option, ctx.qry.head);
html("</select> ");
- html("<input type='submit' name='' value='switch'/>");
+ html("<input type='submit' value='switch'/>");
html("</form>");
}
} else
@@ -1057,6 +1041,11 @@ void cgit_print_pageheader(void)
if (ctx.repo->max_stats)
cgit_stats_link("stats", NULL, hc("stats"),
ctx.qry.head, ctx.qry.vpath);
+ if (ctx.repo->homepage) {
+ html("<a href='");
+ html_attr(ctx.repo->homepage);
+ html("'>homepage</a>");
+ }
html("</td><td class='form'>");
html("<form class='right' method='get' action='");
if (ctx.cfg.virtual_root) {
@@ -1128,18 +1117,34 @@ void cgit_print_filemode(unsigned short mode)
html_fileperm(mode);
}
+void cgit_compose_snapshot_prefix(struct strbuf *filename, const char *base,
+ const char *ref)
+{
+ unsigned char sha1[20];
+
+ /*
+ * Prettify snapshot names by stripping leading "v" or "V" if the tag
+ * name starts with {v,V}[0-9] and the prettify mapping is injective,
+ * i.e. each stripped tag can be inverted without ambiguities.
+ */
+ if (get_sha1(fmt("refs/tags/%s", ref), sha1) == 0 &&
+ (ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1]) &&
+ ((get_sha1(fmt("refs/tags/%s", ref + 1), sha1) == 0) +
+ (get_sha1(fmt("refs/tags/v%s", ref + 1), sha1) == 0) +
+ (get_sha1(fmt("refs/tags/V%s", ref + 1), sha1) == 0) == 1))
+ ref++;
+
+ strbuf_addf(filename, "%s-%s", base, ref);
+}
+
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);
+ cgit_compose_snapshot_prefix(&filename, cgit_repobasename(repo), hex);
prefixlen = filename.len;
for (f = cgit_snapshot_formats; f->suffix; f++) {
if (!(snapshots & f->bit))
diff --git a/ui-shared.h b/ui-shared.h
index 6b4f9aa..aadc271 100644
--- a/ui-shared.h
+++ b/ui-shared.h
@@ -70,8 +70,8 @@ __attribute__((format (printf,1,2)))
extern void cgit_print_error(const char *fmt, ...);
__attribute__((format (printf,1,0)))
extern void cgit_vprint_error(const char *fmt, va_list ap);
-extern void cgit_print_date(time_t secs, const char *format, int local_time);
-extern void cgit_print_age(time_t t, time_t max_relative, const char *format);
+extern const struct date_mode *cgit_date_mode(enum date_mode_type type);
+extern void cgit_print_age(time_t t, int tz, time_t max_relative);
extern void cgit_print_http_headers(void);
extern void cgit_redirect(const char *url, bool permanent);
extern void cgit_print_docstart(void);
@@ -80,6 +80,8 @@ __attribute__((format (printf,3,4)))
extern void cgit_print_error_page(int code, const char *msg, const char *fmt, ...);
extern void cgit_print_pageheader(void);
extern void cgit_print_filemode(unsigned short mode);
+extern void cgit_compose_snapshot_prefix(struct strbuf *filename,
+ const char *base, const char *ref);
extern void cgit_print_snapshot_links(const char *repo, const char *head,
const char *hex, int snapshots);
extern void cgit_add_hidden_formfields(int incl_head, int incl_search,
diff --git a/ui-stats.c b/ui-stats.c
index d2ddfd5..5100de2 100644
--- a/ui-stats.c
+++ b/ui-stats.c
@@ -3,12 +3,6 @@
#include "html.h"
#include "ui-shared.h"
-#ifdef NO_C99_FORMAT
-#define SZ_FMT "%u"
-#else
-#define SZ_FMT "%zu"
-#endif
-
struct authorstat {
long total;
struct string_list list;
@@ -174,6 +168,7 @@ static void add_commit(struct string_list *authors, struct commit *commit,
char *tmp;
struct tm *date;
time_t t;
+ uintptr_t *counter;
info = cgit_parse_commit(commit);
tmp = xstrdup(info->author);
@@ -189,9 +184,11 @@ static void add_commit(struct string_list *authors, struct commit *commit,
period->trunc(date);
tmp = xstrdup(period->pretty(date));
item = string_list_insert(items, tmp);
- if (item->util)
+ counter = (uintptr_t *)&item->util;
+ if (*counter)
free(tmp);
- item->util++;
+ (*counter)++;
+
authorstat->total++;
cgit_free_commitinfo(info);
}
@@ -286,7 +283,7 @@ static void print_combined_authorrow(struct string_list *authors, int from,
items = &authorstat->list;
date = string_list_lookup(items, tmp);
if (date)
- subtotal += (size_t)date->util;
+ subtotal += (uintptr_t)date->util;
}
htmlf("<td class='%s'>%ld</td>", centerclass, subtotal);
total += subtotal;
@@ -340,8 +337,8 @@ static void print_authors(struct string_list *authors, int top,
if (!date)
html("<td>0</td>");
else {
- htmlf("<td>"SZ_FMT"</td>", (size_t)date->util);
- total += (size_t)date->util;
+ htmlf("<td>%lu</td>", (uintptr_t)date->util);
+ total += (uintptr_t)date->util;
}
}
htmlf("<td class='sum'>%ld</td></tr>", total);
@@ -392,7 +389,7 @@ void cgit_show_stats(void)
cgit_print_layout_start();
html("<div class='cgit-panel'>");
html("<b>stat options</b>");
- html("<form method='get' action=''>");
+ html("<form method='get'>");
cgit_add_hidden_formfields(1, 0, "stats");
html("<table><tr><td colspan='2'/></tr>");
if (ctx.repo->max_stats > 1) {
diff --git a/ui-tag.c b/ui-tag.c
index 0afc663..6b838cb 100644
--- a/ui-tag.c
+++ b/ui-tag.c
@@ -76,7 +76,8 @@ void cgit_print_tag(char *revname)
htmlf(" (%s)</td></tr>\n", sha1_to_hex(sha1));
if (info->tagger_date > 0) {
html("<tr><td>tag date</td><td>");
- cgit_print_date(info->tagger_date, FMT_LONGDATE, ctx.cfg.local_time);
+ html_txt(show_date(info->tagger_date, info->tagger_tz,
+ cgit_date_mode(DATE_ISO8601)));
html("</td></tr>\n");
}
if (info->tagger) {