aboutsummaryrefslogtreecommitdiff
path: root/ui-shared.c
diff refs
from: back
to: back
| flip
diff options
context:
space:
mode:
Diffstat (limited to 'ui-shared.c')
-rw-r--r--ui-shared.c233
1 files changed, 32 insertions, 201 deletions
diff --git a/ui-shared.c b/ui-shared.c
index 9eb48a9..151ac17 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -1,26 +1,15 @@
/* ui-shared.c: common web output functions
*
* Copyright (C) 2006-2017 cgit Development Team <cgit@lists.zx2c4.com>
- * Copyright (C) 2026 Saya Andy <saya.andy@posteo.com>
- *
- * Modified 2026 by Saya Andy:
- * Implement ci link tab
- * Check repo existence
- * Replace memrchr() for macOS compatibility
- * Allow multiple favicons of different mime types to be used
- * Include favicon.svg as default
*
* 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 "ui-ci.h"
#include "version.h"
static const char cgit_doctype[] =
@@ -33,11 +22,10 @@ static char *http_date(time_t t)
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);
+ 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, ...)
@@ -351,12 +339,6 @@ void cgit_tag_link(const char *name, const char *title, const char *class,
reporevlink("tag", name, title, class, tag, NULL, NULL);
}
-void cgit_ci_link(const char *name, const char *title, const char *class,
- const char *head)
-{
- reporevlink("ci", name, title, class, head, NULL, NULL);
-}
-
void cgit_tree_link(const char *name, const char *title, const char *class,
const char *head, const char *rev, const char *path)
{
@@ -494,21 +476,6 @@ void cgit_diff_link(const char *name, const char *title, const char *class,
html_url_arg(old_rev);
delim = "&amp;";
}
- /*
- * Emit the ref offsets after the refs so that they follow the
- * refs through file-level links; a zero offset means the ref
- * itself.
- */
- if (ctx.qry.idoff) {
- html(delim);
- htmlf("idoff=%d", ctx.qry.idoff);
- delim = "&amp;";
- }
- if (ctx.qry.id2off) {
- html(delim);
- htmlf("id2off=%d", ctx.qry.id2off);
- delim = "&amp;";
- }
if (ctx.qry.difftype) {
html(delim);
htmlf("dt=%d", ctx.qry.difftype);
@@ -694,18 +661,18 @@ void cgit_submodule_link(const char *class, char *path, const char *rev)
path[len - 1] = tail;
}
-const struct date_mode cgit_date_mode(enum date_mode_type type)
+const struct date_mode *cgit_date_mode(enum date_mode_type type)
{
static struct date_mode mode;
mode.type = type;
mode.local = ctx.cfg.local_time;
- return mode;
+ return &mode;
}
static void print_rel_date(time_t t, int tz, double value,
const char *class, const char *suffix)
{
- htmlf("<span class='%s' data-ut='%" PRIu64 "' title='", class, (uint64_t)t);
+ htmlf("<span class='%s' title='", class);
html_attr(show_date(t, tz, cgit_date_mode(DATE_ISO8601)));
htmlf("'>%.0f %s</span>", value, suffix);
}
@@ -791,51 +758,6 @@ void cgit_redirect(const char *url, bool permanent)
html("\n\n");
}
-static const struct {
- const char *ext;
- const char *mimetype;
-} favicon_mimetypes[] = {
- { "ico", "image/x-icon" },
- { "png", "image/png" },
- { "svg", "image/svg+xml" },
- { "gif", "image/gif" },
- { "jpg", "image/jpeg" },
- { "jpeg", "image/jpeg" },
- { "webp", "image/webp" },
- { "avif", "image/avif" },
-};
-
-/* Deduce the mimetype of a favicon from the extension of its url, ignoring
- * any query string or fragment. Returns NULL for unknown extensions.
- */
-static const char *favicon_mimetype(const char *url)
-{
- const char *p, *end, *ext = NULL;
- size_t len;
- int i;
-
- end = strpbrk(url, "?#");
- if (!end)
- end = url + strlen(url);
-
- for (p = url; p < end; p++) {
- if (*p == '/')
- ext = NULL;
- else if (*p == '.')
- ext = p + 1;
- }
- if (!ext)
- return NULL;
- len = end - ext;
-
- for (i = 0; i < ARRAY_SIZE(favicon_mimetypes); i++) {
- if (strlen(favicon_mimetypes[i].ext) == len &&
- !strncasecmp(favicon_mimetypes[i].ext, ext, len))
- return favicon_mimetypes[i].mimetype;
- }
- return NULL;
-}
-
static void print_rel_vcs_link(const char *url)
{
html("<link rel='vcs-git' href='");
@@ -845,59 +767,6 @@ static void print_rel_vcs_link(const char *url)
html(" Git repository'/>\n");
}
-static int emit_css_link(struct string_list_item *s, void *arg)
-{
- /* Do not emit anything if css= is specified. */
- if (s && *s->string == '\0')
- return 0;
-
- html("<link rel='stylesheet' type='text/css' href='");
- if (s)
- html_attr(s->string);
- else
- html_attr((const char *)arg);
- html("'/>\n");
-
- return 0;
-}
-
-static int emit_js_link(struct string_list_item *s, void *arg)
-{
- /* Do not emit anything if js= is specified. */
- if (s && *s->string == '\0')
- return 0;
-
- html("<script type='text/javascript' src='");
- if (s)
- html_attr(s->string);
- else
- html_attr((const char *)arg);
- html("'></script>\n");
-
- return 0;
-}
-
-static int emit_favicon_link(struct string_list_item *s, void *arg)
-{
- const char *url = s ? s->string : (const char *)arg;
- const char *mimetype;
-
- /* Do not emit anything if favicon= is specified. */
- if (!*url)
- return 0;
-
- html("<link rel='shortcut icon' href='");
- html_attr(url);
- mimetype = favicon_mimetype(url);
- if (mimetype) {
- html("' type='");
- html_attr(mimetype);
- }
- html("'/>\n");
-
- return 0;
-}
-
void cgit_print_docstart(void)
{
char *host = cgit_hosturl();
@@ -917,23 +786,14 @@ void cgit_print_docstart(void)
htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
if (ctx.cfg.robots && *ctx.cfg.robots)
htmlf("<meta name='robots' content='%s'/>\n", ctx.cfg.robots);
-
- if (ctx.cfg.css.items)
- for_each_string_list(&ctx.cfg.css, emit_css_link, NULL);
- else
- emit_css_link(NULL, "/cgit.css");
-
- if (ctx.cfg.js.items)
- for_each_string_list(&ctx.cfg.js, emit_js_link, NULL);
- else
- emit_js_link(NULL, "/cgit.js");
-
- if (ctx.cfg.favicon.items)
- for_each_string_list(&ctx.cfg.favicon, emit_favicon_link, NULL);
- else
- emit_favicon_link(NULL, "/favicon.svg");
- emit_favicon_link(NULL, "/favicon.ico");
-
+ html("<link rel='stylesheet' type='text/css' href='");
+ html_attr(ctx.cfg.css);
+ html("'/>\n");
+ if (ctx.cfg.favicon) {
+ html("<link rel='shortcut icon' href='");
+ html_attr(ctx.cfg.favicon);
+ html("'/>\n");
+ }
if (host && ctx.repo && ctx.qry.head) {
char *fileurl;
struct strbuf sb = STRBUF_INIT;
@@ -974,7 +834,7 @@ void cgit_print_docend(void)
if (ctx.cfg.footer)
html_include(ctx.cfg.footer);
else {
- htmlf("<div class='footer'>generated by <a href='https://sayag.it/cgitext.git/about/'>cgitext %s</a> "
+ htmlf("<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit %s</a> "
"(<a href='https://git-scm.com/'>git %s</a>) at ", cgit_version, git_version_string);
html_txt(show_date(time(NULL), 0, cgit_date_mode(DATE_ISO8601)));
html("</div>\n");
@@ -986,18 +846,13 @@ void cgit_print_docend(void)
void cgit_print_error_page(int code, const char *msg, const char *fmt, ...)
{
va_list ap;
- va_start(ap, fmt);
- cgit_vprint_error_page(code, msg, fmt, ap);
- va_end(ap);
-}
-
-void cgit_vprint_error_page(int code, const char *msg, const char *fmt, va_list ap)
-{
ctx.page.expires = ctx.cfg.cache_dynamic_ttl;
ctx.page.status = code;
ctx.page.statusmsg = msg;
cgit_print_layout_start();
+ va_start(ap, fmt);
cgit_vprint_error(fmt, ap);
+ va_end(ap);
cgit_print_layout_end();
}
@@ -1038,9 +893,10 @@ void cgit_add_clone_urls(void (*fn)(const char *))
add_clone_urls(fn, ctx.cfg.clone_prefix, ctx.repo->url);
}
-static int print_branch_option(const struct reference *ref, void *cb_data)
+static int print_branch_option(const char *refname, const struct object_id *oid,
+ int flags, void *cb_data)
{
- char *name = (char *)ref->name;
+ char *name = (char *)refname;
html_option(name, name, ctx.qry.head);
return 0;
}
@@ -1066,10 +922,6 @@ void cgit_add_hidden_formfields(int incl_head, int incl_search,
html_hidden("id", ctx.qry.oid);
if (ctx.qry.oid2)
html_hidden("id2", ctx.qry.oid2);
- if (ctx.qry.idoff)
- html_hidden("idoff", fmt("%d", ctx.qry.idoff));
- if (ctx.qry.id2off)
- html_hidden("id2off", fmt("%d", ctx.qry.id2off));
if (ctx.qry.showmsg)
html_hidden("showmsg", "1");
@@ -1142,17 +994,15 @@ static void print_header(void)
if (ctx.repo) {
cgit_index_link("index", NULL, NULL, NULL, NULL, 0, 1);
html(" : ");
- cgit_summary_link(ctx.repo->name, NULL, NULL, NULL);
- if (ctx.env.authenticated && cgit_have_repository()) {
+ cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL);
+ if (ctx.env.authenticated) {
html("</td><td class='form'>");
html("<form method='get'>\n");
cgit_add_hidden_formfields(0, 1, ctx.qry.page);
html("<select name='h' onchange='this.form.submit();'>\n");
- refs_for_each_branch_ref(get_main_ref_store(the_repository),
- print_branch_option, ctx.qry.head);
+ for_each_branch_ref(print_branch_option, ctx.qry.head);
if (ctx.repo->enable_remote_branches)
- refs_for_each_remote_ref(get_main_ref_store(the_repository),
- print_branch_option, ctx.qry.head);
+ for_each_remote_ref(print_branch_option, ctx.qry.head);
html("</select> ");
html("<input type='submit' value='switch'/>");
html("</form>");
@@ -1165,13 +1015,7 @@ static void print_header(void)
if (ctx.repo) {
html_txt(ctx.repo->desc);
html("</td><td class='sub right'>");
- if (ctx.repo->owner_filter) {
- cgit_open_filter(ctx.repo->owner_filter);
- html_txt(ctx.repo->owner);
- cgit_close_filter(ctx.repo->owner_filter);
- } else {
- html_txt(ctx.repo->owner);
- }
+ html_txt(ctx.repo->owner);
} else {
if (ctx.cfg.root_desc)
html_txt(ctx.cfg.root_desc);
@@ -1211,8 +1055,6 @@ void cgit_print_pageheader(void)
if (ctx.repo->max_stats)
cgit_stats_link("stats", NULL, hc("stats"),
ctx.qry.head, ctx.qry.vpath);
- if (cgit_ci_available())
- cgit_ci_link("ci", NULL, hc("ci"), ctx.qry.head);
if (ctx.repo->homepage) {
html("<a href='");
html_attr(ctx.repo->homepage);
@@ -1261,7 +1103,7 @@ void cgit_print_pageheader(void)
html("<div class='path'>");
html("path: ");
cgit_print_path_crumbs(ctx.qry.vpath);
- if (ctx.repo->enable_follow_links && !strcmp(ctx.qry.page, "log")) {
+ if (ctx.cfg.enable_follow_links && !strcmp(ctx.qry.page, "log")) {
html(" (");
ctx.qry.follow = !ctx.qry.follow;
cgit_self_link(ctx.qry.follow ? "follow" : "unfollow",
@@ -1299,11 +1141,11 @@ void cgit_compose_snapshot_prefix(struct strbuf *filename, const char *base,
* name starts with {v,V}[0-9] and the prettify mapping is injective,
* i.e. each stripped tag can be inverted without ambiguities.
*/
- if (repo_get_oid(the_repository, fmt("refs/tags/%s", ref), &oid) == 0 &&
+ if (get_oid(fmt("refs/tags/%s", ref), &oid) == 0 &&
(ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1]) &&
- ((repo_get_oid(the_repository, fmt("refs/tags/%s", ref + 1), &oid) == 0) +
- (repo_get_oid(the_repository, fmt("refs/tags/v%s", ref + 1), &oid) == 0) +
- (repo_get_oid(the_repository, fmt("refs/tags/V%s", ref + 1), &oid) == 0) == 1))
+ ((get_oid(fmt("refs/tags/%s", ref + 1), &oid) == 0) +
+ (get_oid(fmt("refs/tags/v%s", ref + 1), &oid) == 0) +
+ (get_oid(fmt("refs/tags/V%s", ref + 1), &oid) == 0) == 1))
ref++;
strbuf_addf(filename, "%s-%s", base, ref);
@@ -1350,17 +1192,6 @@ void cgit_print_snapshot_links(const struct cgit_repo *repo, const char *ref,
strbuf_release(&filename);
}
-/* Locate the last '/' within the first len bytes of path, or NULL if
- * there is none. Avoids memrchr(), which is a GNU extension.
- */
-static const char *find_last_slash(const char *path, size_t len)
-{
- while (len > 0)
- if (path[--len] == '/')
- return path + len;
- return NULL;
-}
-
void cgit_set_title_from_path(const char *path)
{
struct strbuf sb = STRBUF_INIT;
@@ -1369,7 +1200,7 @@ void cgit_set_title_from_path(const char *path)
if (!path)
return;
- for (last_slash = path + strlen(path); (slash = find_last_slash(path, last_slash - path)) != NULL; last_slash = slash) {
+ for (last_slash = path + strlen(path); (slash = memrchr(path, '/', last_slash - path)) != NULL; last_slash = slash) {
strbuf_add(&sb, slash + 1, last_slash - slash - 1);
strbuf_addstr(&sb, " \xc2\xab ");
}