Warmcat homepage andy@warmcat.com
libwebsockets
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"", "gen_ut":1714086777, "reponame":"cgit", "desc":"CGI gitweb", "owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://warmcat.com/repo/cgit", "f":3, "items": [ {"schema":"libjg2-1", "cid":"52fe26c791776fcb889dbb7b233c3cdf", "oid":{ "oid": "d1bb699526842f656f7afa799431003ab285dac2", "alias": [ "refs/heads/decruft","refs/heads/master"]},"blobname": "ui-shared.c", "blob": "/* ui-shared.c: common web output functions\n *\n * Copyright (C) 2006-2017 cgit Development Team \u003ccgit@lists.zx2c4.com\u003e\n *\n * Licensed under GNU General Public License v2\n * (see COPYING for full license text)\n */\n\n#include \u0022cgit.h\u0022\n#include \u0022ui-shared.h\u0022\n#include \u0022cmd.h\u0022\n#include \u0022html.h\u0022\n#include \u0022version.h\u0022\n\nstatic const char cgit_doctype[] \u003d\n\u0022\u003c!DOCTYPE html\u003e\u005cn\u0022;\n\nstatic char *http_date(time_t t)\n{\n\tstatic char day[][4] \u003d\n\t\t{\u0022Sun\u0022, \u0022Mon\u0022, \u0022Tue\u0022, \u0022Wed\u0022, \u0022Thu\u0022, \u0022Fri\u0022, \u0022Sat\u0022};\n\tstatic char month[][4] \u003d\n\t\t{\u0022Jan\u0022, \u0022Feb\u0022, \u0022Mar\u0022, \u0022Apr\u0022, \u0022May\u0022, \u0022Jun\u0022,\n\t\t \u0022Jul\u0022, \u0022Aug\u0022, \u0022Sep\u0022, \u0022Oct\u0022, \u0022Nov\u0022, \u0022Dec\u0022};\n\tstruct tm *tm \u003d gmtime(\u0026t);\n\treturn fmt(\u0022%s, %02d %s %04d %02d:%02d:%02d GMT\u0022, day[tm-\u003etm_wday],\n\t\t tm-\u003etm_mday, month[tm-\u003etm_mon], 1900 + tm-\u003etm_year,\n\t\t tm-\u003etm_hour, tm-\u003etm_min, tm-\u003etm_sec);\n}\n\nvoid cgit_print_error(const char *fmt, ...)\n{\n\tva_list ap;\n\tva_start(ap, fmt);\n\tcgit_vprint_error(fmt, ap);\n\tva_end(ap);\n}\n\nvoid cgit_vprint_error(const char *fmt, va_list ap)\n{\n\tva_list cp;\n\thtml(\u0022\u003cdiv class\u003d'error'\u003e\u0022);\n\tva_copy(cp, ap);\n\thtml_vtxtf(fmt, cp);\n\tva_end(cp);\n\thtml(\u0022\u003c/div\u003e\u005cn\u0022);\n}\n\nconst char *cgit_httpscheme(void)\n{\n\tif (ctx.env.https \u0026\u0026 !strcmp(ctx.env.https, \u0022on\u0022))\n\t\treturn \u0022https://\u0022;\n\telse\n\t\treturn \u0022http://\u0022;\n}\n\nchar *cgit_hosturl(void)\n{\n\tif (ctx.env.http_host)\n\t\treturn xstrdup(ctx.env.http_host);\n\tif (!ctx.env.server_name)\n\t\treturn NULL;\n\tif (!ctx.env.server_port || atoi(ctx.env.server_port) \u003d\u003d 80)\n\t\treturn xstrdup(ctx.env.server_name);\n\treturn fmtalloc(\u0022%s:%s\u0022, ctx.env.server_name, ctx.env.server_port);\n}\n\nchar *cgit_currenturl(void)\n{\n\tconst char *root \u003d cgit_rooturl();\n\tsize_t len \u003d strlen(root);\n\n\tif (!ctx.qry.url)\n\t\treturn xstrdup(root);\n\tif (len \u0026\u0026 root[len - 1] \u003d\u003d '/')\n\t\treturn fmtalloc(\u0022%s%s\u0022, root, ctx.qry.url);\n\treturn fmtalloc(\u0022%s/%s\u0022, root, ctx.qry.url);\n}\n\nconst char *cgit_rooturl(void)\n{\n\tif (ctx.cfg.virtual_root)\n\t\treturn ctx.cfg.virtual_root;\n\telse\n\t\treturn ctx.cfg.script_name;\n}\n\nconst char *cgit_loginurl(void)\n{\n\tstatic const char *login_url;\n\tif (!login_url)\n\t\tlogin_url \u003d fmtalloc(\u0022%s?p\u003dlogin\u0022, cgit_rooturl());\n\treturn login_url;\n}\n\nchar *cgit_repourl(const char *reponame)\n{\n\tif (ctx.cfg.virtual_root)\n\t\treturn fmtalloc(\u0022%s%s/\u0022, ctx.cfg.virtual_root, reponame);\n\telse\n\t\treturn fmtalloc(\u0022?r\u003d%s\u0022, reponame);\n}\n\nchar *cgit_fileurl(const char *reponame, const char *pagename,\n\t\t const char *filename, const char *query)\n{\n\tstruct strbuf sb \u003d STRBUF_INIT;\n\tchar *delim;\n\n\tif (ctx.cfg.virtual_root) {\n\t\tstrbuf_addf(\u0026sb, \u0022%s%s/%s/%s\u0022, ctx.cfg.virtual_root, reponame,\n\t\t\t pagename, (filename ? filename:\u0022\u0022));\n\t\tdelim \u003d \u0022?\u0022;\n\t} else {\n\t\tstrbuf_addf(\u0026sb, \u0022?url\u003d%s/%s/%s\u0022, reponame, pagename,\n\t\t\t (filename ? filename : \u0022\u0022));\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (query)\n\t\tstrbuf_addf(\u0026sb, \u0022%s%s\u0022, delim, query);\n\treturn strbuf_detach(\u0026sb, NULL);\n}\n\nchar *cgit_pageurl(const char *reponame, const char *pagename,\n\t\t const char *query)\n{\n\treturn cgit_fileurl(reponame, pagename, NULL, query);\n}\n\n/* result is NULL or must be freed */\nstatic char *cgit_repobasename(const char *reponame)\n{\n\tint last \u003d strlen(reponame) - 1, n;\n\tchar *rv;\n\n\tif (last \u003c 1)\n\t\treturn NULL;\n\n\twhile (last \u0026\u0026 reponame[last] \u003d\u003d '/')\n\t\tlast--;\n\n\tif (last \u003e\u003d 3 \u0026\u0026 !strncmp(\u0026reponame[last - 3], \u0022.git\u0022, 3))\n\t\tlast -\u003d 3;\n\n\twhile (last \u0026\u0026 reponame[last] \u003d\u003d '/')\n\t\tlast--;\n\n\tn \u003d last;\n\twhile (n \u0026\u0026 reponame[n] !\u003d '/')\n\t\tn--;\n\n\trv \u003d xmalloc(last - n + 2);\n\tstrncpy(rv, \u0026reponame[n], last - n + 1);\n\trv[last - n + 1] \u003d '\u005c0';\n\n\treturn rv;\n}\n\n/* result is NULL or must be freed */\nchar *cgit_snapshot_prefix(const struct cgit_repo *repo)\n{\n\tif (repo-\u003esnapshot_prefix)\n\t\treturn xstrdup(repo-\u003esnapshot_prefix);\n\n\treturn cgit_repobasename(repo-\u003eurl);\n}\n\nstatic void site_url(const char *page, const char *search, const char *sort, int ofs, int always_root)\n{\n\tchar *delim \u003d \u0022?\u0022;\n\n\tif (always_root || page)\n\t\thtml_attr(cgit_rooturl());\n\telse {\n\t\tchar *currenturl \u003d cgit_currenturl();\n\t\thtml_attr(currenturl);\n\t\tfree(currenturl);\n\t}\n\n\tif (page) {\n\t\thtmlf(\u0022?p\u003d%s\u0022, page);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (search) {\n\t\thtml(delim);\n\t\thtml(\u0022q\u003d\u0022);\n\t\thtml_attr(search);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (sort) {\n\t\thtml(delim);\n\t\thtml(\u0022s\u003d\u0022);\n\t\thtml_attr(sort);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (ofs) {\n\t\thtml(delim);\n\t\thtmlf(\u0022ofs\u003d%d\u0022, ofs);\n\t}\n}\n\nstatic void site_link(const char *page, const char *name, const char *title,\n\t\t const char *class, const char *search, const char *sort, int ofs, int always_root)\n{\n\thtml(\u0022\u003ca\u0022);\n\tif (title) {\n\t\thtml(\u0022 title\u003d'\u0022);\n\t\thtml_attr(title);\n\t\thtml(\u0022'\u0022);\n\t}\n\tif (class) {\n\t\thtml(\u0022 class\u003d'\u0022);\n\t\thtml_attr(class);\n\t\thtml(\u0022'\u0022);\n\t}\n\thtml(\u0022 href\u003d'\u0022);\n\tsite_url(page, search, sort, ofs, always_root);\n\thtml(\u0022'\u003e\u0022);\n\thtml_txt(name);\n\thtml(\u0022\u003c/a\u003e\u0022);\n}\n\nvoid cgit_index_link(const char *name, const char *title, const char *class,\n\t\t const char *pattern, const char *sort, int ofs, int always_root)\n{\n\tsite_link(NULL, name, title, class, pattern, sort, ofs, always_root);\n}\n\nconst char *cgit_repo_create_url(struct strbuf *sb, struct strbuf *sb_post,\n\t\t\t\t const char *page, const char *head,\n\t\t\t\t const char *path)\n{\n\tconst char *delim \u003d \u0022?\u0022;\n\n\tif (ctx.cfg.virtual_root) {\n\t\tstrbuf_addf(sb, \u0022%s%s\u0022, ctx.cfg.virtual_root, ctx.repo-\u003eurl);\n\t} else {\n\t\tstrbuf_addstr(sb, ctx.cfg.script_name);\n\t\tsb \u003d sb_post;\n\t\tstrbuf_addf(sb, \u0022?url\u003d%s\u0022, ctx.repo-\u003eurl);\n\t\tdelim \u003d \u0022\u0026\u0022;\n\t}\n\n\tif (ctx.repo-\u003eurl[strlen(ctx.repo-\u003eurl) - 1] !\u003d '/')\n\t\tstrbuf_addch(sb, '/');\n\n\tif (page) {\n\t\tstrbuf_addf(sb, \u0022%s/\u0022, page);\n\t\tif (path)\n\t\t\tstrbuf_addstr(sb, path);\n\t}\n\n\tif (head \u0026\u0026 ctx.repo-\u003edefbranch \u0026\u0026 strcmp(head, ctx.repo-\u003edefbranch)) {\n\t\tstrbuf_addf(sb_post, \u0022%sh\u003d%s\u0022, delim, head);\n\t\tdelim \u003d \u0022\u0026\u0022;\n\t}\n\n\treturn delim;\n}\n\nstatic char *repolink(const char *title, const char *class, const char *page,\n\t\t const char *head, const char *path)\n{\n\tchar *delim \u003d \u0022?\u0022;\n\n\thtml(\u0022\u003ca\u0022);\n\tif (title) {\n\t\thtml(\u0022 title\u003d'\u0022);\n\t\thtml_attr(title);\n\t\thtml(\u0022'\u0022);\n\t}\n\tif (class) {\n\t\thtml(\u0022 class\u003d'\u0022);\n\t\thtml_attr(class);\n\t\thtml(\u0022'\u0022);\n\t}\n\thtml(\u0022 href\u003d'\u0022);\n\tif (ctx.cfg.virtual_root) {\n\t\thtml_url_path(ctx.cfg.virtual_root);\n\t\thtml_url_path(ctx.repo-\u003eurl);\n\t\tif (ctx.repo-\u003eurl[strlen(ctx.repo-\u003eurl) - 1] !\u003d '/')\n\t\t\thtml(\u0022/\u0022);\n\t\tif (page) {\n\t\t\thtml_url_path(page);\n\t\t\thtml(\u0022/\u0022);\n\t\t\tif (path)\n\t\t\t\thtml_url_path(path);\n\t\t}\n\t} else {\n\t\thtml_url_path(ctx.cfg.script_name);\n\t\thtml(\u0022?url\u003d\u0022);\n\t\thtml_url_arg(ctx.repo-\u003eurl);\n\t\tif (ctx.repo-\u003eurl[strlen(ctx.repo-\u003eurl) - 1] !\u003d '/')\n\t\t\thtml(\u0022/\u0022);\n\t\tif (page) {\n\t\t\thtml_url_arg(page);\n\t\t\thtml(\u0022/\u0022);\n\t\t\tif (path)\n\t\t\t\thtml_url_arg(path);\n\t\t}\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (head \u0026\u0026 ctx.repo-\u003edefbranch \u0026\u0026 strcmp(head, ctx.repo-\u003edefbranch)) {\n\t\thtml(delim);\n\t\thtml(\u0022h\u003d\u0022);\n\t\thtml_url_arg(head);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\treturn fmt(\u0022%s\u0022, delim);\n}\n\nstatic void reporevlink(const char *page, const char *name, const char *title,\n\t\t\tconst char *class, const char *head, const char *rev,\n\t\t\tconst char *path)\n{\n\tchar *delim;\n\n\tdelim \u003d repolink(title, class, page, head, path);\n\tif (rev \u0026\u0026 ctx.qry.head !\u003d NULL \u0026\u0026 strcmp(rev, ctx.qry.head)) {\n\t\thtml(delim);\n\t\thtml(\u0022id\u003d\u0022);\n\t\thtml_url_arg(rev);\n\t}\n\thtml(\u0022'\u003e\u0022);\n\thtml_txt(name);\n\thtml(\u0022\u003c/a\u003e\u0022);\n}\n\nvoid cgit_summary_link(const char *name, const char *title, const char *class,\n\t\t const char *head)\n{\n\treporevlink(NULL, name, title, class, head, NULL, NULL);\n}\n\nvoid cgit_tag_link(const char *name, const char *title, const char *class,\n\t\t const char *tag)\n{\n\treporevlink(\u0022tag\u0022, name, title, class, tag, NULL, NULL);\n}\n\nvoid cgit_tree_link(const char *name, const char *title, const char *class,\n\t\t const char *head, const char *rev, const char *path)\n{\n\treporevlink(\u0022tree\u0022, name, title, class, head, rev, path);\n}\n\nvoid cgit_plain_link(const char *name, const char *title, const char *class,\n\t\t const char *head, const char *rev, const char *path)\n{\n\treporevlink(\u0022plain\u0022, name, title, class, head, rev, path);\n}\n\nvoid cgit_blame_link(const char *name, const char *title, const char *class,\n\t\t const char *head, const char *rev, const char *path)\n{\n\treporevlink(\u0022blame\u0022, name, title, class, head, rev, path);\n}\n\nvoid cgit_log_link(const char *name, const char *title, const char *class,\n\t\t const char *head, const char *rev, const char *path,\n\t\t int ofs, const char *grep, const char *pattern, int showmsg,\n\t\t int follow)\n{\n\tchar *delim;\n\n\tdelim \u003d repolink(title, class, \u0022log\u0022, head, path);\n\tif (rev \u0026\u0026 ctx.qry.head \u0026\u0026 strcmp(rev, ctx.qry.head)) {\n\t\thtml(delim);\n\t\thtml(\u0022id\u003d\u0022);\n\t\thtml_url_arg(rev);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (grep \u0026\u0026 pattern) {\n\t\thtml(delim);\n\t\thtml(\u0022qt\u003d\u0022);\n\t\thtml_url_arg(grep);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t\thtml(delim);\n\t\thtml(\u0022q\u003d\u0022);\n\t\thtml_url_arg(pattern);\n\t}\n\tif (ofs \u003e 0) {\n\t\thtml(delim);\n\t\thtml(\u0022ofs\u003d\u0022);\n\t\thtmlf(\u0022%d\u0022, ofs);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (showmsg) {\n\t\thtml(delim);\n\t\thtml(\u0022showmsg\u003d1\u0022);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (follow) {\n\t\thtml(delim);\n\t\thtml(\u0022follow\u003d1\u0022);\n\t}\n\thtml(\u0022'\u003e\u0022);\n\thtml_txt(name);\n\thtml(\u0022\u003c/a\u003e\u0022);\n}\n\nvoid cgit_commit_link(const char *name, const char *title, const char *class,\n\t\t const char *head, const char *rev, const char *path)\n{\n\tchar *delim;\n\n\tdelim \u003d repolink(title, class, \u0022commit\u0022, head, path);\n\tif (rev \u0026\u0026 ctx.qry.head \u0026\u0026 strcmp(rev, ctx.qry.head)) {\n\t\thtml(delim);\n\t\thtml(\u0022id\u003d\u0022);\n\t\thtml_url_arg(rev);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (ctx.qry.difftype) {\n\t\thtml(delim);\n\t\thtmlf(\u0022dt\u003d%d\u0022, ctx.qry.difftype);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (ctx.qry.context \u003e 0 \u0026\u0026 ctx.qry.context !\u003d 3) {\n\t\thtml(delim);\n\t\thtml(\u0022context\u003d\u0022);\n\t\thtmlf(\u0022%d\u0022, ctx.qry.context);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (ctx.qry.ignorews) {\n\t\thtml(delim);\n\t\thtml(\u0022ignorews\u003d1\u0022);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (ctx.qry.follow) {\n\t\thtml(delim);\n\t\thtml(\u0022follow\u003d1\u0022);\n\t}\n\thtml(\u0022'\u003e\u0022);\n\tif (name[0] !\u003d '\u005c0') {\n\t\tif (strlen(name) \u003e ctx.cfg.max_msg_len \u0026\u0026 ctx.cfg.max_msg_len \u003e\u003d 15) {\n\t\t\thtml_ntxt(name, ctx.cfg.max_msg_len - 3);\n\t\t\thtml(\u0022...\u0022);\n\t\t} else\n\t\t\thtml_txt(name);\n\t} else\n\t\thtml_txt(\u0022(no commit message)\u0022);\n\thtml(\u0022\u003c/a\u003e\u0022);\n}\n\nvoid cgit_refs_link(const char *name, const char *title, const char *class,\n\t\t const char *head, const char *rev, const char *path)\n{\n\treporevlink(\u0022refs\u0022, name, title, class, head, rev, path);\n}\n\nvoid cgit_snapshot_link(const char *name, const char *title, const char *class,\n\t\t\tconst char *head, const char *rev,\n\t\t\tconst char *archivename)\n{\n\treporevlink(\u0022snapshot\u0022, name, title, class, head, rev, archivename);\n}\n\nvoid cgit_diff_link(const char *name, const char *title, const char *class,\n\t\t const char *head, const char *new_rev, const char *old_rev,\n\t\t const char *path)\n{\n\tchar *delim;\n\n\tdelim \u003d repolink(title, class, \u0022diff\u0022, head, path);\n\tif (new_rev \u0026\u0026 ctx.qry.head !\u003d NULL \u0026\u0026 strcmp(new_rev, ctx.qry.head)) {\n\t\thtml(delim);\n\t\thtml(\u0022id\u003d\u0022);\n\t\thtml_url_arg(new_rev);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (old_rev) {\n\t\thtml(delim);\n\t\thtml(\u0022id2\u003d\u0022);\n\t\thtml_url_arg(old_rev);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (ctx.qry.difftype) {\n\t\thtml(delim);\n\t\thtmlf(\u0022dt\u003d%d\u0022, ctx.qry.difftype);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (ctx.qry.context \u003e 0 \u0026\u0026 ctx.qry.context !\u003d 3) {\n\t\thtml(delim);\n\t\thtml(\u0022context\u003d\u0022);\n\t\thtmlf(\u0022%d\u0022, ctx.qry.context);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (ctx.qry.ignorews) {\n\t\thtml(delim);\n\t\thtml(\u0022ignorews\u003d1\u0022);\n\t\tdelim \u003d \u0022\u0026amp;\u0022;\n\t}\n\tif (ctx.qry.follow) {\n\t\thtml(delim);\n\t\thtml(\u0022follow\u003d1\u0022);\n\t}\n\thtml(\u0022'\u003e\u0022);\n\thtml_txt(name);\n\thtml(\u0022\u003c/a\u003e\u0022);\n}\n\nvoid cgit_patch_link(const char *name, const char *title, const char *class,\n\t\t const char *head, const char *rev, const char *path)\n{\n\treporevlink(\u0022patch\u0022, name, title, class, head, rev, path);\n}\n\nvoid cgit_stats_link(const char *name, const char *title, const char *class,\n\t\t const char *head, const char *path)\n{\n\treporevlink(\u0022stats\u0022, name, title, class, head, NULL, path);\n}\n\nstatic void cgit_self_link(char *name, const char *title, const char *class)\n{\n\tif (!strcmp(ctx.qry.page, \u0022repolist\u0022))\n\t\tcgit_index_link(name, title, class, ctx.qry.search, ctx.qry.sort,\n\t\t\t\tctx.qry.ofs, 1);\n\telse if (!strcmp(ctx.qry.page, \u0022summary\u0022))\n\t\tcgit_summary_link(name, title, class, ctx.qry.head);\n\telse if (!strcmp(ctx.qry.page, \u0022tag\u0022))\n\t\tcgit_tag_link(name, title, class, ctx.qry.has_sha1 ?\n\t\t\t ctx.qry.sha1 : ctx.qry.head);\n\telse if (!strcmp(ctx.qry.page, \u0022tree\u0022))\n\t\tcgit_tree_link(name, title, class, ctx.qry.head,\n\t\t\t ctx.qry.has_sha1 ? ctx.qry.sha1 : NULL,\n\t\t\t ctx.qry.path);\n\telse if (!strcmp(ctx.qry.page, \u0022plain\u0022))\n\t\tcgit_plain_link(name, title, class, ctx.qry.head,\n\t\t\t\tctx.qry.has_sha1 ? ctx.qry.sha1 : NULL,\n\t\t\t\tctx.qry.path);\n\telse if (!strcmp(ctx.qry.page, \u0022blame\u0022))\n\t\tcgit_blame_link(name, title, class, ctx.qry.head,\n\t\t\t\tctx.qry.has_sha1 ? ctx.qry.sha1 : NULL,\n\t\t\t\tctx.qry.path);\n\telse if (!strcmp(ctx.qry.page, \u0022log\u0022))\n\t\tcgit_log_link(name, title, class, ctx.qry.head,\n\t\t\t ctx.qry.has_sha1 ? ctx.qry.sha1 : NULL,\n\t\t\t ctx.qry.path, ctx.qry.ofs,\n\t\t\t ctx.qry.grep, ctx.qry.search,\n\t\t\t ctx.qry.showmsg, ctx.qry.follow);\n\telse if (!strcmp(ctx.qry.page, \u0022commit\u0022))\n\t\tcgit_commit_link(name, title, class, ctx.qry.head,\n\t\t\t\t ctx.qry.has_sha1 ? ctx.qry.sha1 : NULL,\n\t\t\t\t ctx.qry.path);\n\telse if (!strcmp(ctx.qry.page, \u0022patch\u0022))\n\t\tcgit_patch_link(name, title, class, ctx.qry.head,\n\t\t\t\tctx.qry.has_sha1 ? ctx.qry.sha1 : NULL,\n\t\t\t\tctx.qry.path);\n\telse if (!strcmp(ctx.qry.page, \u0022refs\u0022))\n\t\tcgit_refs_link(name, title, class, ctx.qry.head,\n\t\t\t ctx.qry.has_sha1 ? ctx.qry.sha1 : NULL,\n\t\t\t ctx.qry.path);\n\telse if (!strcmp(ctx.qry.page, \u0022snapshot\u0022))\n\t\tcgit_snapshot_link(name, title, class, ctx.qry.head,\n\t\t\t\t ctx.qry.has_sha1 ? ctx.qry.sha1 : NULL,\n\t\t\t\t ctx.qry.path);\n\telse if (!strcmp(ctx.qry.page, \u0022diff\u0022))\n\t\tcgit_diff_link(name, title, class, ctx.qry.head,\n\t\t\t ctx.qry.sha1, ctx.qry.sha2,\n\t\t\t ctx.qry.path);\n\telse if (!strcmp(ctx.qry.page, \u0022stats\u0022))\n\t\tcgit_stats_link(name, title, class, ctx.qry.head,\n\t\t\t\tctx.qry.path);\n\telse {\n\t\t/* Don't known how to make link for this page */\n\t\trepolink(title, class, ctx.qry.page, ctx.qry.head, ctx.qry.path);\n\t\thtml(\u0022\u003e\u003c!-- cgit_self_link() doesn't know how to make link for page '\u0022);\n\t\thtml_txt(ctx.qry.page);\n\t\thtml(\u0022' --\u003e\u0022);\n\t\thtml_txt(name);\n\t\thtml(\u0022\u003c/a\u003e\u0022);\n\t}\n}\n\nvoid cgit_object_link(struct object *obj)\n{\n\tchar *page, *shortrev, *fullrev, *name;\n\n\tfullrev \u003d oid_to_hex(\u0026obj-\u003eoid);\n\tshortrev \u003d xstrdup(fullrev);\n\tshortrev[10] \u003d '\u005c0';\n\tif (obj-\u003etype \u003d\u003d OBJ_COMMIT) {\n\t\tcgit_commit_link(fmt(\u0022commit %s...\u0022, shortrev), NULL, NULL,\n\t\t\t\t ctx.qry.head, fullrev, NULL);\n\t\treturn;\n\t} else if (obj-\u003etype \u003d\u003d OBJ_TREE)\n\t\tpage \u003d \u0022tree\u0022;\n\telse if (obj-\u003etype \u003d\u003d OBJ_TAG)\n\t\tpage \u003d \u0022tag\u0022;\n\telse\n\t\tpage \u003d \u0022blob\u0022;\n\tname \u003d fmt(\u0022%s %s...\u0022, type_name(obj-\u003etype), shortrev);\n\treporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL);\n}\n\nstatic struct string_list_item *lookup_path(struct string_list *list,\n\t\t\t\t\t const char *path)\n{\n\tstruct string_list_item *item;\n\n\twhile (path \u0026\u0026 path[0]) {\n\t\tif ((item \u003d string_list_lookup(list, path)))\n\t\t\treturn item;\n\t\tif (!(path \u003d strchr(path, '/')))\n\t\t\tbreak;\n\t\tpath++;\n\t}\n\treturn NULL;\n}\n\nvoid cgit_submodule_link(const char *class, char *path, const char *rev)\n{\n\tstruct string_list *list;\n\tstruct string_list_item *item;\n\tchar tail, *dir;\n\tsize_t len;\n\n\tlen \u003d 0;\n\ttail \u003d 0;\n\tlist \u003d \u0026ctx.repo-\u003esubmodules;\n\titem \u003d lookup_path(list, path);\n\tif (!item) {\n\t\tlen \u003d strlen(path);\n\t\ttail \u003d path[len - 1];\n\t\tif (tail \u003d\u003d '/') {\n\t\t\tpath[len - 1] \u003d 0;\n\t\t\titem \u003d lookup_path(list, path);\n\t\t}\n\t}\n\tif (item || ctx.repo-\u003emodule_link) {\n\t\thtml(\u0022\u003ca \u0022);\n\t\tif (class)\n\t\t\thtmlf(\u0022class\u003d'%s' \u0022, class);\n\t\thtml(\u0022href\u003d'\u0022);\n\t\tif (item) {\n\t\t\thtml_attrf(item-\u003eutil, rev);\n\t\t} else {\n\t\t\tdir \u003d strrchr(path, '/');\n\t\t\tif (dir)\n\t\t\t\tdir++;\n\t\t\telse\n\t\t\t\tdir \u003d path;\n\t\t\thtml_attrf(ctx.repo-\u003emodule_link, dir, rev);\n\t\t}\n\t\thtml(\u0022'\u003e\u0022);\n\t\thtml_txt(path);\n\t\thtml(\u0022\u003c/a\u003e\u0022);\n\t} else {\n\t\thtml(\u0022\u003cspan\u0022);\n\t\tif (class)\n\t\t\thtmlf(\u0022 class\u003d'%s'\u0022, class);\n\t\thtml(\u0022\u003e\u0022);\n\t\thtml_txt(path);\n\t\thtml(\u0022\u003c/span\u003e\u0022);\n\t}\n\thtml_txtf(\u0022 @ %.7s\u0022, rev);\n\tif (item \u0026\u0026 tail)\n\t\tpath[len - 1] \u003d tail;\n}\n\nconst struct date_mode *cgit_date_mode(enum date_mode_type type)\n{\n\tstatic struct date_mode mode;\n\tmode.type \u003d type;\n\tmode.local \u003d ctx.cfg.local_time;\n\treturn \u0026mode;\n}\n\nstatic void print_rel_date(time_t t, int tz, double value,\n\tconst char *class, const char *suffix)\n{\n\thtmlf(\u0022\u003cspan class\u003d'%s' ut\u003d'%\u0022 PRIu64 \u0022' title\u003d'\u0022, class, (uint64_t)t);\n\thtml_attr(show_date(t, tz, cgit_date_mode(DATE_ISO8601)));\n\thtmlf(\u0022'\u003e%.0f %s\u003c/span\u003e\u0022, value, suffix);\n}\n\nvoid cgit_print_age(time_t t, int tz, time_t max_relative)\n{\n\ttime_t now, secs;\n\n\tif (!t)\n\t\treturn;\n\ttime(\u0026now);\n\tsecs \u003d now - t;\n\tif (secs \u003c 0)\n\t\tsecs \u003d 0;\n\n\tif (secs \u003e max_relative \u0026\u0026 max_relative \u003e\u003d 0) {\n\t\thtml(\u0022\u003cspan title\u003d'\u0022);\n\t\thtml_attr(show_date(t, tz, cgit_date_mode(DATE_ISO8601)));\n\t\thtml(\u0022'\u003e\u0022);\n\t\thtml_txt(show_date(t, tz, cgit_date_mode(DATE_SHORT)));\n\t\thtml(\u0022\u003c/span\u003e\u0022);\n\t\treturn;\n\t}\n\n\tif (secs \u003c TM_HOUR * 2) {\n\t\tprint_rel_date(t, tz, secs * 1.0 / TM_MIN, \u0022age-mins\u0022, \u0022min.\u0022);\n\t\treturn;\n\t}\n\tif (secs \u003c TM_DAY * 2) {\n\t\tprint_rel_date(t, tz, secs * 1.0 / TM_HOUR, \u0022age-hours\u0022, \u0022hours\u0022);\n\t\treturn;\n\t}\n\tif (secs \u003c TM_WEEK * 2) {\n\t\tprint_rel_date(t, tz, secs * 1.0 / TM_DAY, \u0022age-days\u0022, \u0022days\u0022);\n\t\treturn;\n\t}\n\tif (secs \u003c TM_MONTH * 2) {\n\t\tprint_rel_date(t, tz, secs * 1.0 / TM_WEEK, \u0022age-weeks\u0022, \u0022weeks\u0022);\n\t\treturn;\n\t}\n\tif (secs \u003c TM_YEAR * 2) {\n\t\tprint_rel_date(t, tz, secs * 1.0 / TM_MONTH, \u0022age-months\u0022, \u0022months\u0022);\n\t\treturn;\n\t}\n\tprint_rel_date(t, tz, secs * 1.0 / TM_YEAR, \u0022age-years\u0022, \u0022years\u0022);\n}\n\nvoid cgit_print_http_headers(void)\n{\n\tif (ctx.env.no_http \u0026\u0026 !strcmp(ctx.env.no_http, \u00221\u0022))\n\t\treturn;\n\n\tif (ctx.page.status)\n\t\thtmlf(\u0022Status: %d %s\u005cn\u0022, ctx.page.status, ctx.page.statusmsg);\n\tif (ctx.page.mimetype \u0026\u0026 ctx.page.charset)\n\t\thtmlf(\u0022Content-Type: %s; charset\u003d%s\u005cn\u0022, ctx.page.mimetype,\n\t\t ctx.page.charset);\n\telse if (ctx.page.mimetype)\n\t\thtmlf(\u0022Content-Type: %s\u005cn\u0022, ctx.page.mimetype);\n\tif (ctx.page.size)\n\t\thtmlf(\u0022Content-Length: %zd\u005cn\u0022, ctx.page.size);\n\tif (ctx.page.filename) {\n\t\thtml(\u0022Content-Disposition: inline; filename\u003d\u005c\u0022\u0022);\n\t\thtml_header_arg_in_quotes(ctx.page.filename);\n\t\thtml(\u0022\u005c\u0022\u005cn\u0022);\n\t}\n\tif (!ctx.env.authenticated)\n\t\thtml(\u0022Cache-Control: no-cache, no-store\u005cn\u0022);\n\thtmlf(\u0022Last-Modified: %s\u005cn\u0022, http_date(ctx.page.modified));\n\thtmlf(\u0022Expires: %s\u005cn\u0022, http_date(ctx.page.expires));\n\tif (ctx.page.etag)\n\t\thtmlf(\u0022ETag: \u005c\u0022%s\u005c\u0022\u005cn\u0022, ctx.page.etag);\n\thtml(\u0022\u005cn\u0022);\n\tif (ctx.env.request_method \u0026\u0026 !strcmp(ctx.env.request_method, \u0022HEAD\u0022))\n\t\texit(0);\n}\n\nvoid cgit_redirect(const char *url, bool permanent)\n{\n\thtmlf(\u0022Status: %d %s\u005cn\u0022, permanent ? 301 : 302, permanent ? \u0022Moved\u0022 : \u0022Found\u0022);\n\thtml(\u0022Location: \u0022);\n\thtml_url_path(url);\n\thtml(\u0022\u005cn\u005cn\u0022);\n}\n\nstatic void print_rel_vcs_link(const char *url)\n{\n\thtml(\u0022\u003clink rel\u003d'vcs-git' href\u003d'\u0022);\n\thtml_attr(url);\n\thtml(\u0022' title\u003d'\u0022);\n\thtml_attr(ctx.repo-\u003ename);\n\thtml(\u0022 Git repository'/\u003e\u005cn\u0022);\n}\n\nstatic int emit_css_link(struct string_list_item *s, void *arg)\n{\n\thtml(\u0022\u003clink rel\u003d'stylesheet' type\u003d'text/css' href\u003d'\u0022);\n\tif (s)\n\t\thtml_attr(s-\u003estring);\n\telse\n\t\thtml_attr((const char *)arg);\n\thtml(\u0022'/\u003e\u005cn\u0022);\n\n\treturn 0;\n}\n\t\nstatic int emit_js_link(struct string_list_item *s, void *arg)\n{\n\thtml(\u0022\u003cscript type\u003d'text/javascript' src\u003d'\u0022);\n\thtml_attr(s-\u003estring);\n\thtml(\u0022'\u003e\u003c/script\u003e\u005cn\u0022);\n\n\treturn 0;\n}\n\nvoid cgit_print_docstart(void)\n{\n\tchar *host \u003d cgit_hosturl();\n\n\tif (ctx.cfg.embedded) {\n\t\tif (ctx.cfg.header)\n\t\t\thtml_include(ctx.cfg.header);\n\t\treturn;\n\t}\n\n\thtml(cgit_doctype);\n\thtml(\u0022\u003chtml lang\u003d'en'\u003e\u005cn\u0022);\n\thtml(\u0022\u003chead\u003e\u005cn\u0022);\n\thtml(\u0022\u003ctitle\u003e\u0022);\n\thtml_txt(ctx.page.title);\n\thtml(\u0022\u003c/title\u003e\u005cn\u0022);\n\thtmlf(\u0022\u003cmeta name\u003d'generator' content\u003d'cgit %s'/\u003e\u005cn\u0022, cgit_version);\n\tif (ctx.cfg.robots \u0026\u0026 *ctx.cfg.robots)\n\t\thtmlf(\u0022\u003cmeta name\u003d'robots' content\u003d'%s'/\u003e\u005cn\u0022, ctx.cfg.robots);\n\n\tif (ctx.cfg.css.items)\n\t\tfor_each_string_list(\u0026ctx.cfg.css, emit_css_link, NULL);\n\telse\n\t\temit_css_link(NULL, \u0022/cgit.css\u0022);\n\n\tfor_each_string_list(\u0026ctx.cfg.js, emit_js_link, NULL);\n\n\tif (ctx.cfg.favicon) {\n\t\thtml(\u0022\u003clink rel\u003d'shortcut icon' href\u003d'\u0022);\n\t\thtml_attr(ctx.cfg.favicon);\n\t\thtml(\u0022'/\u003e\u005cn\u0022);\n\t}\n\tif (host \u0026\u0026 ctx.repo \u0026\u0026 ctx.qry.head) {\n\t\tchar *fileurl;\n\t\tstruct strbuf sb \u003d STRBUF_INIT;\n\t\tstrbuf_addf(\u0026sb, \u0022h\u003d%s\u0022, ctx.qry.head);\n\n\t\thtml(\u0022\u003clink rel\u003d'alternate' title\u003d'Atom feed' href\u003d'\u0022);\n\t\thtml(cgit_httpscheme());\n\t\thtml_attr(host);\n\t\tfileurl \u003d cgit_fileurl(ctx.repo-\u003eurl, \u0022atom\u0022, ctx.qry.vpath,\n\t\t\t\t sb.buf);\n\t\thtml_attr(fileurl);\n\t\thtml(\u0022' type\u003d'application/atom+xml'/\u003e\u005cn\u0022);\n\t\tstrbuf_release(\u0026sb);\n\t\tfree(fileurl);\n\t}\n\tif (ctx.repo)\n\t\tcgit_add_clone_urls(print_rel_vcs_link);\n\tif (ctx.cfg.head_include)\n\t\thtml_include(ctx.cfg.head_include);\n\thtml(\u0022\u003c/head\u003e\u005cn\u0022);\n\thtml(\u0022\u003cbody\u003e\u005cn\u0022);\n\tif (ctx.cfg.header)\n\t\thtml_include(ctx.cfg.header);\n\tfree(host);\n}\n\nvoid cgit_print_docend(void)\n{\n\thtml(\u0022\u003c/div\u003e \u003c!-- class\u003dcontent --\u003e\u005cn\u0022);\n\tif (ctx.cfg.embedded) {\n\t\thtml(\u0022\u003c/div\u003e \u003c!-- id\u003dcgit --\u003e\u005cn\u0022);\n\t\tif (ctx.cfg.footer)\n\t\t\thtml_include(ctx.cfg.footer);\n\t\treturn;\n\t}\n\tif (ctx.cfg.footer)\n\t\thtml_include(ctx.cfg.footer);\n\telse {\n\t\thtmlf(\u0022\u003cdiv class\u003d'footer'\u003egenerated by \u003ca href\u003d'https://git.zx2c4.com/cgit/about/'\u003ecgit %s\u003c/a\u003e \u0022\n\t\t\t\u0022(\u003ca href\u003d'https://git-scm.com/'\u003egit %s\u003c/a\u003e) at \u0022, cgit_version, git_version_string);\n\t\thtml_txt(show_date(time(NULL), 0, cgit_date_mode(DATE_ISO8601)));\n\t\thtml(\u0022 (\u0022);\n\t\tcgit_print_age(time(NULL), 0, -1);\n\t\thtml(\u0022 ago)\u003c/div\u003e\u005cn\u0022);\n\t}\n\thtml(\u0022\u003c/div\u003e \u003c!-- id\u003dcgit --\u003e\u005cn\u0022);\n\thtml(\u0022\u003c/body\u003e\u005cn\u003c/html\u003e\u005cn\u0022);\n}\n\nvoid cgit_print_error_page(int code, const char *msg, const char *fmt, ...)\n{\n\tva_list ap;\n\tctx.page.expires \u003d ctx.cfg.cache_dynamic_ttl;\n\tctx.page.status \u003d code;\n\tctx.page.statusmsg \u003d msg;\n\tcgit_print_layout_start();\n\tva_start(ap, fmt);\n\tcgit_vprint_error(fmt, ap);\n\tva_end(ap);\n\tcgit_print_layout_end();\n}\n\nvoid cgit_print_layout_start(void)\n{\n\tcgit_print_http_headers();\n\tcgit_print_docstart();\n\tcgit_print_pageheader();\n}\n\nvoid cgit_print_layout_end(void)\n{\n\tcgit_print_docend();\n}\n\nstatic void add_clone_urls(void (*fn)(const char *), char *txt, char *suffix)\n{\n\tstruct strbuf **url_list \u003d strbuf_split_str(txt, ' ', 0);\n\tint i;\n\n\tfor (i \u003d 0; url_list[i]; i++) {\n\t\tstrbuf_rtrim(url_list[i]);\n\t\tif (url_list[i]-\u003elen \u003d\u003d 0)\n\t\t\tcontinue;\n\t\tif (suffix \u0026\u0026 *suffix)\n\t\t\tstrbuf_addf(url_list[i], \u0022/%s\u0022, suffix);\n\t\tfn(url_list[i]-\u003ebuf);\n\t}\n\n\tstrbuf_list_free(url_list);\n}\n\nvoid cgit_add_clone_urls(void (*fn)(const char *))\n{\n\tif (ctx.repo-\u003eclone_url)\n\t\tadd_clone_urls(fn, expand_macros(ctx.repo-\u003eclone_url), NULL);\n\telse if (ctx.cfg.clone_prefix)\n\t\tadd_clone_urls(fn, ctx.cfg.clone_prefix, ctx.repo-\u003eurl);\n}\n\nstatic int print_branch_option(const char *refname, const struct object_id *oid,\n\t\t\t int flags, void *cb_data)\n{\n\tchar *name \u003d (char *)refname;\n\thtml_option(name, name, ctx.qry.head);\n\treturn 0;\n}\n\nvoid cgit_add_hidden_formfields(int incl_head, int incl_search,\n\t\t\t\tconst char *page)\n{\n\tif (!ctx.cfg.virtual_root) {\n\t\tstruct strbuf url \u003d STRBUF_INIT;\n\n\t\tstrbuf_addf(\u0026url, \u0022%s/%s\u0022, ctx.qry.repo, page);\n\t\tif (ctx.qry.vpath)\n\t\t\tstrbuf_addf(\u0026url, \u0022/%s\u0022, ctx.qry.vpath);\n\t\thtml_hidden(\u0022url\u0022, url.buf);\n\t\tstrbuf_release(\u0026url);\n\t}\n\n\tif (incl_head \u0026\u0026 ctx.qry.head \u0026\u0026 ctx.repo-\u003edefbranch \u0026\u0026\n\t strcmp(ctx.qry.head, ctx.repo-\u003edefbranch))\n\t\thtml_hidden(\u0022h\u0022, ctx.qry.head);\n\n\tif (ctx.qry.sha1)\n\t\thtml_hidden(\u0022id\u0022, ctx.qry.sha1);\n\tif (ctx.qry.sha2)\n\t\thtml_hidden(\u0022id2\u0022, ctx.qry.sha2);\n\tif (ctx.qry.showmsg)\n\t\thtml_hidden(\u0022showmsg\u0022, \u00221\u0022);\n\n\tif (incl_search) {\n\t\tif (ctx.qry.grep)\n\t\t\thtml_hidden(\u0022qt\u0022, ctx.qry.grep);\n\t\tif (ctx.qry.search)\n\t\t\thtml_hidden(\u0022q\u0022, ctx.qry.search);\n\t}\n}\n\nstatic const char *hc(const char *page)\n{\n\tif (!ctx.qry.page)\n\t\treturn NULL;\n\n\treturn strcmp(ctx.qry.page, page) ? NULL : \u0022active\u0022;\n}\n\nstatic void cgit_print_path_crumbs(char *path)\n{\n\tchar *old_path \u003d ctx.qry.path;\n\tchar *p \u003d path, *q, *end \u003d path + strlen(path);\n\n\tctx.qry.path \u003d NULL;\n\tcgit_self_link(\u0022root\u0022, NULL, NULL);\n\tctx.qry.path \u003d p \u003d path;\n\twhile (p \u003c end) {\n\t\tif (!(q \u003d strchr(p, '/')))\n\t\t\tq \u003d end;\n\t\t*q \u003d '\u005c0';\n\t\thtml_txt(\u0022/\u0022);\n\t\tcgit_self_link(p, NULL, NULL);\n\t\tif (q \u003c end)\n\t\t\t*q \u003d '/';\n\t\tp \u003d q + 1;\n\t}\n\tctx.qry.path \u003d old_path;\n}\n\nstatic void print_branch_combo_form(void)\n{\n\thtml(\u0022\u003cform method\u003d'get'\u003e\u005cn\u0022);\n\tcgit_add_hidden_formfields(0, 1, ctx.qry.page);\n\thtml(\u0022\u003cselect name\u003d'h' onchange\u003d'this.form.submit();'\u003e\u005cn\u0022);\n\tfor_each_branch_ref(print_branch_option, ctx.qry.head);\n\tif (ctx.repo-\u003eenable_remote_branches)\n\t\tfor_each_remote_ref(print_branch_option, ctx.qry.head);\n\thtml(\u0022\u003c/select\u003e \u0022);\n\thtml(\u0022\u003cinput type\u003d'submit' value\u003d'switch'/\u003e\u0022);\n\thtml(\u0022\u003c/form\u003e\u0022);\n}\n\nstatic void print_header(void)\n{\n\tchar *logo \u003d NULL, *logo_link \u003d NULL;\n\n\thtml(\u0022\u003ctable id\u003d'header'\u003e\u005cn\u0022);\n\thtml(\u0022\u003ctr\u003e\u005cn\u0022);\n\n\tif (ctx.repo \u0026\u0026 ctx.repo-\u003elogo \u0026\u0026 *ctx.repo-\u003elogo)\n\t\tlogo \u003d ctx.repo-\u003elogo;\n\telse\n\t\tlogo \u003d ctx.cfg.logo;\n\tif (ctx.repo \u0026\u0026 ctx.repo-\u003elogo_link \u0026\u0026 *ctx.repo-\u003elogo_link)\n\t\tlogo_link \u003d ctx.repo-\u003elogo_link;\n\telse\n\t\tlogo_link \u003d ctx.cfg.logo_link;\n\tif (logo \u0026\u0026 *logo) {\n\t\thtml(\u0022\u003ctd class\u003d'logo' rowspan\u003d'2'\u003e\u003ca href\u003d'\u0022);\n\t\tif (logo_link \u0026\u0026 *logo_link)\n\t\t\thtml_attr(logo_link);\n\t\telse\n\t\t\thtml_attr(cgit_rooturl());\n\t\thtml(\u0022'\u003e\u003cimg src\u003d'\u0022);\n\t\thtml_attr(logo);\n\t\thtml(\u0022' alt\u003d'cgit logo'/\u003e\u003c/a\u003e\u003c/td\u003e\u005cn\u0022);\n\t}\n\n\thtml(\u0022\u003ctd class\u003d'main'\u003e\u0022);\n\tif (ctx.repo) {\n\t\tcgit_index_link(\u0022index\u0022, NULL, NULL, NULL, NULL, 0, 1);\n\t\thtml(\u0022 : \u0022);\n\t\tcgit_summary_link(ctx.repo-\u003ename, ctx.repo-\u003ename, NULL, NULL);\n\t\tif (ctx.env.authenticated) {\n\t\t\thtml(\u0022\u003c/td\u003e\u003ctd class\u003d'form'\u003e\u0022);\n\t\t\tprint_branch_combo_form();\n\t\t}\n\t} else\n\t\thtml_txt(ctx.cfg.root_title);\n\thtml(\u0022\u003c/td\u003e\u003c/tr\u003e\u005cn\u0022);\n\n\thtml(\u0022\u003ctr\u003e\u003ctd class\u003d'sub'\u003e\u0022);\n\tif (ctx.repo) {\n\t\tif (ctx.repo-\u003edesc \u0026\u0026\n\t\t (ctx.repo-\u003edesc !\u003d cgit_default_repo_desc ||\n\t\t !ctx.repo-\u003edesc_html))\n\t\t\thtml_txt(ctx.repo-\u003edesc);\n\t\tif (ctx.repo-\u003edesc_html)\n\t\t\thtml(ctx.repo-\u003edesc_html);\n\t\thtml(\u0022\u003c/td\u003e\u003ctd class\u003d'sub right'\u003e\u0022);\n\t\thtml_txt(ctx.repo-\u003eowner);\n\t} else {\n\t\tif (ctx.cfg.root_desc)\n\t\t\thtml_txt(ctx.cfg.root_desc);\n\t\tif (ctx.cfg.root_desc_html)\n\t\t\thtml(ctx.cfg.root_desc_html);\n\t}\n\thtml(\u0022\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u005cn\u0022);\n}\n\nvoid cgit_print_pageheader(void)\n{\n\thtml(\u0022\u003cdiv id\u003d'cgit'\u003e\u0022);\n\tif (!ctx.env.authenticated || !ctx.cfg.noheader)\n\t\tprint_header();\n\n\thtml(\u0022\u003ctable class\u003d'tabs'\u003e\u003ctr\u003e\u005cn\u0022);\n\tif (ctx.env.authenticated \u0026\u0026 ctx.repo) {\n\t\tif (ctx.cfg.noheader) {\n\t\t\thtml(\u0022\u003ctd class\u003d'form' style\u003d'text-align:left'\u003e\u0022);\n\t\t\tprint_branch_combo_form();\n\t\t\thtml(\u0022\u003c/td\u003e\u003ctd style\u003d'text-align:center'\u003e\u0022);\n\t\t}\n\t\thtml(\u0022\u003ctd\u003e\u0022);\n\n\t\tcgit_summary_link(\u0022summary\u0022, NULL, hc(\u0022summary\u0022),\n\t\t\t\t ctx.qry.head);\n\t\tcgit_refs_link(\u0022refs\u0022, NULL, hc(\u0022refs\u0022), ctx.qry.head,\n\t\t\t ctx.qry.sha1, NULL);\n\t\tcgit_log_link(\u0022log\u0022, NULL, hc(\u0022log\u0022), ctx.qry.head,\n\t\t\t NULL, ctx.qry.vpath, 0, NULL, NULL,\n\t\t\t ctx.qry.showmsg, ctx.qry.follow);\n\t\tif (ctx.qry.page \u0026\u0026 !strcmp(ctx.qry.page, \u0022blame\u0022))\n\t\t\tcgit_blame_link(\u0022blame\u0022, NULL, hc(\u0022blame\u0022), ctx.qry.head,\n\t\t\t\t ctx.qry.sha1, ctx.qry.vpath);\n\t\telse\n\t\t\tcgit_tree_link(\u0022tree\u0022, NULL, hc(\u0022tree\u0022), ctx.qry.head,\n\t\t\t\t ctx.qry.sha1, ctx.qry.vpath);\n\t\tcgit_commit_link(\u0022commit\u0022, NULL, hc(\u0022commit\u0022),\n\t\t\t\t ctx.qry.head, ctx.qry.sha1, ctx.qry.vpath);\n\t\tcgit_diff_link(\u0022diff\u0022, NULL, hc(\u0022diff\u0022), ctx.qry.head,\n\t\t\t ctx.qry.sha1, ctx.qry.sha2, ctx.qry.vpath);\n\t\tif (ctx.repo-\u003emax_stats)\n\t\t\tcgit_stats_link(\u0022stats\u0022, NULL, hc(\u0022stats\u0022),\n\t\t\t\t\tctx.qry.head, ctx.qry.vpath);\n\t\tif (ctx.repo-\u003ehomepage) {\n\t\t\thtml(\u0022\u003ca href\u003d'\u0022);\n\t\t\thtml_attr(ctx.repo-\u003ehomepage);\n\t\t\thtml(\u0022'\u003ehomepage\u003c/a\u003e\u0022);\n\t\t}\n\t\thtml(\u0022\u003c/td\u003e\u003ctd class\u003d'form'\u003e\u0022);\n\t\thtml(\u0022\u003cform class\u003d'right' method\u003d'get' action\u003d'\u0022);\n\t\tif (ctx.cfg.virtual_root) {\n\t\t\tchar *fileurl \u003d cgit_fileurl(ctx.qry.repo, \u0022log\u0022,\n\t\t\t\t\t\t ctx.qry.vpath, NULL);\n\t\t\thtml_url_path(fileurl);\n\t\t\tfree(fileurl);\n\t\t}\n\t\thtml(\u0022'\u003e\u005cn\u0022);\n\t\tcgit_add_hidden_formfields(1, 0, \u0022log\u0022);\n\t\thtml(\u0022\u003cselect name\u003d'qt'\u003e\u005cn\u0022);\n\t\thtml_option(\u0022grep\u0022, \u0022log msg\u0022, ctx.qry.grep);\n\t\thtml_option(\u0022author\u0022, \u0022author\u0022, ctx.qry.grep);\n\t\thtml_option(\u0022committer\u0022, \u0022committer\u0022, ctx.qry.grep);\n\t\thtml_option(\u0022range\u0022, \u0022range\u0022, ctx.qry.grep);\n\t\thtml(\u0022\u003c/select\u003e\u005cn\u0022);\n\t\thtml(\u0022\u003cinput class\u003d'txt' type\u003d'search' size\u003d'10' name\u003d'q' value\u003d'\u0022);\n\t\thtml_attr(ctx.qry.search);\n\t\thtml(\u0022'/\u003e\u005cn\u0022);\n\t\thtml(\u0022\u003cinput type\u003d'submit' value\u003d'search'/\u003e\u005cn\u0022);\n\t\thtml(\u0022\u003c/form\u003e\u005cn\u0022);\n\t} else if (ctx.env.authenticated) {\n\t\tchar *currenturl \u003d cgit_currenturl();\n\n\t\thtml(\u0022\u003ctd\u003e\u0022);\n\t\tsite_link(NULL, \u0022index\u0022, NULL, hc(\u0022repolist\u0022), NULL, NULL, 0, 1);\n\t\thtml(\u0022\u003c/td\u003e\u003ctd class\u003d'form'\u003e\u0022);\n\t\thtml(\u0022\u003cform method\u003d'get' action\u003d'\u0022);\n\t\thtml_attr(currenturl);\n\t\thtml(\u0022'\u003e\u005cn\u0022);\n\t\thtml(\u0022\u003cinput type\u003d'search' name\u003d'q' size\u003d'10' value\u003d'\u0022);\n\t\thtml_attr(ctx.qry.search);\n\t\thtml(\u0022'/\u003e\u005cn\u0022);\n\t\thtml(\u0022\u003cinput type\u003d'submit' value\u003d'search'/\u003e\u005cn\u0022);\n\t\thtml(\u0022\u003c/form\u003e\u0022);\n\t\tfree(currenturl);\n\t}\n\thtml(\u0022\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u005cn\u0022);\n\tif (ctx.env.authenticated \u0026\u0026 ctx.repo \u0026\u0026 ctx.qry.vpath) {\n\t\thtml(\u0022\u003cdiv class\u003d'path'\u003e\u0022);\n\t\thtml(\u0022path: \u0022);\n\t\tcgit_print_path_crumbs(ctx.qry.vpath);\n\t\tif (ctx.cfg.enable_follow_links \u0026\u0026 !strcmp(ctx.qry.page, \u0022log\u0022)) {\n\t\t\thtml(\u0022 (\u0022);\n\t\t\tctx.qry.follow \u003d !ctx.qry.follow;\n\t\t\tcgit_self_link(ctx.qry.follow ? \u0022follow\u0022 : \u0022unfollow\u0022,\n\t\t\t\t\tNULL, NULL);\n\t\t\tctx.qry.follow \u003d !ctx.qry.follow;\n\t\t\thtml(\u0022)\u0022);\n\t\t}\n\t\thtml(\u0022\u003c/div\u003e\u0022);\n\t}\n\thtml(\u0022\u003cdiv class\u003d'content'\u003e\u0022);\n}\n\nvoid cgit_print_filemode(unsigned short mode)\n{\n\tif (S_ISDIR(mode))\n\t\thtml(\u0022d\u0022);\n\telse if (S_ISLNK(mode))\n\t\thtml(\u0022l\u0022);\n\telse if (S_ISGITLINK(mode))\n\t\thtml(\u0022m\u0022);\n\telse\n\t\thtml(\u0022-\u0022);\n\thtml_fileperm(mode \u003e\u003e 6);\n\thtml_fileperm(mode \u003e\u003e 3);\n\thtml_fileperm(mode);\n}\n\nvoid cgit_compose_snapshot_prefix(struct strbuf *filename, const char *base,\n\t\t\t\t const char *ref)\n{\n\tstruct object_id oid;\n\n\t/*\n\t * Prettify snapshot names by stripping leading \u0022v\u0022 or \u0022V\u0022 if the tag\n\t * name starts with {v,V}[0-9] and the prettify mapping is injective,\n\t * i.e. each stripped tag can be inverted without ambiguities.\n\t */\n\tif (get_oid(fmt(\u0022refs/tags/%s\u0022, ref), \u0026oid) \u003d\u003d 0 \u0026\u0026\n\t (ref[0] \u003d\u003d 'v' || ref[0] \u003d\u003d 'V') \u0026\u0026 isdigit(ref[1]) \u0026\u0026\n\t ((get_oid(fmt(\u0022refs/tags/%s\u0022, ref + 1), \u0026oid) \u003d\u003d 0) +\n\t (get_oid(fmt(\u0022refs/tags/v%s\u0022, ref + 1), \u0026oid) \u003d\u003d 0) +\n\t (get_oid(fmt(\u0022refs/tags/V%s\u0022, ref + 1), \u0026oid) \u003d\u003d 0) \u003d\u003d 1))\n\t\tref++;\n\n\tstrbuf_addf(filename, \u0022%s-%s\u0022, base, ref);\n}\n\nvoid cgit_print_snapshot_links(const struct cgit_repo *repo, const char *ref,\n\t\t\t const char *separator)\n{\n\tconst struct cgit_snapshot_format* f;\n\tstruct strbuf filename \u003d STRBUF_INIT;\n\tconst char *basename;\n\tsize_t prefixlen;\n\n\tbasename \u003d cgit_snapshot_prefix(repo);\n\tif (starts_with(ref, basename))\n\t\tstrbuf_addstr(\u0026filename, ref);\n\telse\n\t\tcgit_compose_snapshot_prefix(\u0026filename, basename, ref);\n\n\tprefixlen \u003d filename.len;\n\tfor (f \u003d cgit_snapshot_formats; f-\u003esuffix; f++) {\n\t\tif (!(repo-\u003esnapshots \u0026 cgit_snapshot_format_bit(f)))\n\t\t\tcontinue;\n\t\tstrbuf_setlen(\u0026filename, prefixlen);\n\t\tstrbuf_addstr(\u0026filename, f-\u003esuffix);\n\t\tcgit_snapshot_link(filename.buf, NULL, NULL, NULL, NULL,\n\t\t\t\t filename.buf);\n\t\tif (cgit_snapshot_get_sig(ref, f)) {\n\t\t\tstrbuf_addstr(\u0026filename, \u0022.asc\u0022);\n\t\t\thtml(\u0022 (\u0022);\n\t\t\tcgit_snapshot_link(\u0022sig\u0022, NULL, NULL, NULL, NULL,\n\t\t\t\t\t filename.buf);\n\t\t\thtml(\u0022)\u0022);\n\t\t}\n\t\thtml(separator);\n\t}\n\tstrbuf_release(\u0026filename);\n}\n\nvoid cgit_set_title_from_path(const char *path)\n{\n\tsize_t path_len, path_index, path_last_end;\n\tchar *new_title;\n\n\tif (!path)\n\t\treturn;\n\n\tpath_len \u003d strlen(path);\n\tnew_title \u003d xmalloc(path_len + 3 + strlen(ctx.page.title) + 1);\n\tnew_title[0] \u003d '\u005c0';\n\n\tfor (path_index \u003d path_len, path_last_end \u003d path_len; path_index-- \u003e 0;) {\n\t\tif (path[path_index] \u003d\u003d '/') {\n\t\t\tif (path_index \u003d\u003d path_len - 1) {\n\t\t\t\tpath_last_end \u003d path_index - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tstrncat(new_title, \u0026path[path_index + 1], path_last_end - path_index - 1);\n\t\t\tstrcat(new_title, \u0022\u005c\u005c\u0022);\n\t\t\tpath_last_end \u003d path_index;\n\t\t}\n\t}\n\tif (path_last_end)\n\t\tstrncat(new_title, path, path_last_end);\n\n\tstrcat(new_title, \u0022 - \u0022);\n\tstrcat(new_title, ctx.page.title);\n\tctx.page.title \u003d new_title;\n}\n","s":{"c":1713680198,"u": 15058}} ],"g": 9857,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "7d0a"}