+
+char *cgit_rooturl()
+{
+ if (cgit_virtual_root)
+ return fmt("%s/", cgit_virtual_root);
+ else
+ return cgit_script_name;
+}
+
+char *cgit_repourl(const char *reponame)
+{
+ if (cgit_virtual_root) {
+ return fmt("%s/%s/", cgit_virtual_root, reponame);
+ } else {
+ return fmt("?r=%s", reponame);
+ }
+}
+
+char *cgit_pageurl(const char *reponame, const char *pagename,
+ const char *query)
+{
+ if (cgit_virtual_root) {
+ if (query)
+ return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame,
+ pagename, query);
+ else
+ return fmt("%s/%s/%s/", cgit_virtual_root, reponame,
+ pagename);
+ } else {
+ if (query)
+ return fmt("?r=%s&p=%s&%s", reponame, pagename, query);
+ else
+ return fmt("?r=%s&p=%s", reponame, pagename);
+ }
+}
+
+char *cgit_currurl()
+{
+ if (!cgit_virtual_root)
+ return cgit_script_name;
+ else if (cgit_query_page)
+ return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page);
+ else if (cgit_query_repo)
+ return fmt("%s/%s/", cgit_virtual_root, cgit_query_repo);
+ else
+ return fmt("%s/", cgit_virtual_root);
+}
+
+static char *repolink(char *title, char *class, char *page, char *head,
+ 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 (cgit_virtual_root) {
+ html_attr(cgit_virtual_root);
+ if (cgit_virtual_root[strlen(cgit_virtual_root) - 1] != '/')
+ html("/");
+ html_attr(cgit_repo->url);
+ if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/')
+ html("/");
+ html(page);
+ html("/");
+ if (path)
+ html_attr(path);
+ } else {
+ html(cgit_script_name);
+ html("?url=");
+ html_attr(cgit_repo->url);
+ if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/')
+ html("/");
+ html(page);
+ html("/");
+ if (path)
+ html_attr(path);
+ delim = "&";
+ }
+ if (head && strcmp(head, cgit_query_head)) {
+ html(delim);
+ html("h=");
+ html_attr(head);
+ delim = "&";
+ }
+ return fmt("%s", delim);
+}
+
+void cgit_tree_link(char *name, char *title, char *class, char *head,
+ char *rev, char *path)
+{
+ char *delim;
+
+ delim = repolink(title, class, "tree", head, path);
+ if (rev && strcmp(rev, cgit_query_head)) {
+ html(delim);
+ html("id=");
+ html_attr(rev);
+ }
+ html("'>");
+ html_txt(name);
+ html("</a>");
+}
+
+void cgit_print_date(time_t secs, char *format)
+{
+ char buf[64];
+ struct tm *time;
+
+ time = gmtime(&secs);
+ strftime(buf, sizeof(buf)-1, format, time);
+ html_txt(buf);
+}
+
+void cgit_print_age(time_t t, time_t max_relative, char *format)
+{
+ time_t now, secs;
+
+ time(&now);
+ secs = now - t;
+
+ if (secs > max_relative && max_relative >= 0) {
+ cgit_print_date(t, format);
+ return;
+ }
+
+ if (secs < TM_HOUR * 2) {
+ htmlf("<span class='age-mins'>%.0f min.</span>",
+ secs * 1.0 / TM_MIN);
+ return;
+ }
+ if (secs < TM_DAY * 2) {
+ htmlf("<span class='age-hours'>%.0f hours</span>",
+ secs * 1.0 / TM_HOUR);
+ return;
+ }
+ if (secs < TM_WEEK * 2) {
+ htmlf("<span class='age-days'>%.0f days</span>",
+ secs * 1.0 / TM_DAY);
+ return;
+ }
+ if (secs < TM_MONTH * 2) {
+ htmlf("<span class='age-weeks'>%.0f weeks</span>",
+ secs * 1.0 / TM_WEEK);
+ return;
+ }
+ if (secs < TM_YEAR * 2) {
+ htmlf("<span class='age-months'>%.0f months</span>",
+ secs * 1.0 / TM_MONTH);
+ return;
+ }
+ htmlf("<span class='age-years'>%.0f years</span>",
+ secs * 1.0 / TM_YEAR);
+}
+