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 = "&"; } if (search) { html(delim); html("q="); html_attr(search); delim = "&"; } if (sort) { html(delim); html("s="); html_attr(sort); delim = "&"; } if (ofs) { html(delim); htmlf("ofs=%d", ofs); } }
static void site_url(const char *page, const char *search, const char *sort, int ofs) { char *delim = "?"; if (ctx.cfg.virtual_root) html_attr(ctx.cfg.virtual_root); else html_url_path(ctx.cfg.script_name); if (page) { htmlf("?p=%s", page); delim = "&"; } if (search) { html(delim); html("q="); html_attr(search); delim = "&"; } if (sort) { html(delim); html("s="); html_attr(sort); delim = "&"; } if (ofs) { html(delim); htmlf("ofs=%d", ofs); } }
static void site_url(char *page, char *search, int ofs) { char *delim = "?"; if (ctx.cfg.virtual_root) { html_attr(ctx.cfg.virtual_root); if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/') html("/"); } else html(ctx.cfg.script_name); if (page) { htmlf("?p=%s", page); delim = "&"; } if (search) { html(delim); html("q="); html_attr(search); delim = "&"; } if (ofs) { html(delim); htmlf("ofs=%d", ofs); } }
static void print_dir(const unsigned char *sha1, const char *base, int baselen, const char *path) { char *fullpath, *slash; size_t len; fullpath = buildpath(base, baselen, path); slash = (fullpath[0] == '/' ? "" : "/"); ctx.page.etag = sha1_to_hex(sha1); cgit_print_http_headers(); htmlf("<html><head><title>%s", slash); html_txt(fullpath); htmlf("</title></head>\n<body>\n<h2>%s", slash); html_txt(fullpath); html("</h2>\n<ul>\n"); len = strlen(fullpath); if (len > 1) { fullpath[len - 1] = 0; slash = strrchr(fullpath, '/'); if (slash) *(slash + 1) = 0; else { free(fullpath); fullpath = NULL; } html("<li>"); cgit_plain_link("../", NULL, NULL, ctx.qry.head, ctx.qry.sha1, fullpath); html("</li>\n"); } free(fullpath); }
void print_sort_header(const char *title, const char *sort) { htmlf("<th class='left'><a href='%s?s=%s", cgit_rooturl(), sort); if (ctx.qry.search) { html("&q="); html_url_arg(ctx.qry.search); } htmlf("'>%s</a></th>", title); }
static void print_sort_header(const char *title, const char *sort) { html("<th class='left'><a href='"); html_attr(cgit_currenturl()); htmlf("?s=%s", sort); if (ctx.qry.search) { html("&q="); html_url_arg(ctx.qry.search); } htmlf("'>%s</a></th>", title); }
static void header(unsigned char *sha1, char *path1, int mode1, unsigned char *sha2, char *path2, int mode2) { char *abbrev1, *abbrev2; int subproject; subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2)); htmlf("diff --git a/%s b/%s\n", path1, path2); if (is_null_sha1(sha1)) path1 = "dev/null"; if (is_null_sha1(sha2)) path2 = "dev/null"; if (mode1 == 0) htmlf("new file mode %.6o\n", mode2); if (mode2 == 0) htmlf("deleted file mode %.6o\n", mode1); if (!subproject) { abbrev1 = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV)); abbrev2 = xstrdup(find_unique_abbrev(sha2, DEFAULT_ABBREV)); htmlf("index %s..%s", abbrev1, abbrev2); free(abbrev1); free(abbrev2); if (mode1 != 0 && mode2 != 0) { htmlf(" %.6o", mode1); if (mode2 != mode1) htmlf("..%.6o", mode2); } htmlf("\n--- a/%s\n", path1); htmlf("+++ b/%s\n", path2); } }
static int print_ref_info(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { struct object *obj; if (!(obj = parse_object(sha1))) return 0; htmlf("%s\t%s\n", sha1_to_hex(sha1), refname); if (obj->type == OBJ_TAG) { if (!(obj = deref_tag(obj, refname, 0))) return 0; htmlf("%s\t%s^{}\n", sha1_to_hex(obj->sha1), refname); } return 0; }
static void cgit_print_diffstat(const struct object_id *old_oid, const struct object_id *new_oid, const char *prefix) { int i; html("<div class='diffstat-header'>"); cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1, ctx.qry.sha2, NULL); if (prefix) { html(" (limited to '"); html_txt(prefix); html("')"); } html("</div>"); html("<table summary='diffstat' class='diffstat'>"); max_changes = 0; cgit_diff_tree(old_oid, new_oid, inspect_filepair, prefix, ctx.qry.ignorews); for (i = 0; i<files; i++) print_fileinfo(&items[i]); html("</table>"); html("<div class='diffstat-summary'>"); htmlf("%d files changed, %d insertions, %d deletions", files, total_adds, total_rems); html("</div>"); }
void html_intoption(int value, const char *text, int selected_value) { htmlf("<option value='%d'%s>", value, value == selected_value ? " selected='selected'" : ""); html_txt(text); html("</option>"); }
static void print_line(char *line, int len) { char c = line[len-1]; line[len-1] = '\0'; htmlf("%s\n", line); line[len-1] = c; }
static void emit_blame_entry_linenumber(struct blame_entry *ent) { const char *numberfmt = "<a id='n%1$d' href='#n%1$d'>%1$d</a>\n"; unsigned long lineno = ent->lno; while (lineno < ent->lno + ent->num_lines) htmlf(numberfmt, ++lineno); }
/* Create a sorted string_list with one entry per author. The util-field * for each author is another string_list which is used to calculate the * number of commits per time-interval. */ void cgit_show_stats(struct cgit_context *ctx) { struct string_list authors; struct cgit_period *period; int top, i; const char *code = "w"; if (ctx->qry.period) code = ctx->qry.period; i = cgit_find_stats_period(code, &period); if (!i) { cgit_print_error(fmt("Unknown statistics type: %c", code)); return; } if (i > ctx->repo->max_stats) { cgit_print_error(fmt("Statistics type disabled: %s", period->name)); return; } authors = collect_stats(ctx, period); qsort(authors.items, authors.nr, sizeof(struct string_list_item), cmp_total_commits); top = ctx->qry.ofs; if (!top) top = 10; htmlf("<h2>Commits per author per %s", period->name); if (ctx->qry.path) { html(" (path '"); html_txt(ctx->qry.path); html("')"); } html("</h2>"); html("<form method='get' action='' style='float: right; text-align: right;'>"); cgit_add_hidden_formfields(1, 0, "stats"); if (ctx->repo->max_stats > 1) { html("Period: "); html("<select name='period' onchange='this.form.submit();'>"); for (i = 0; i < ctx->repo->max_stats; i++) htmlf("<option value='%c'%s>%s</option>", periods[i].code, period == &periods[i] ? " selected" : "", periods[i].name); html("</select><br/><br/>"); } html("Authors: "); html(""); html("<select name='ofs' onchange='this.form.submit();'>"); htmlf("<option value='10'%s>10</option>", top == 10 ? " selected" : ""); htmlf("<option value='25'%s>25</option>", top == 25 ? " selected" : ""); htmlf("<option value='50'%s>50</option>", top == 50 ? " selected" : ""); htmlf("<option value='100'%s>100</option>", top == 100 ? " selected" : ""); htmlf("<option value='-1'%s>All</option>", top == -1 ? " selected" : ""); html("</select>"); html("<noscript> <input type='submit' value='Reload'/></noscript>"); html("</form>"); print_authors(&authors, top, period); }
static void print_dir_entry(const unsigned char *sha1, const char *path, unsigned mode) { const char *sep = ""; if (S_ISDIR(mode)) sep = "/"; htmlf(" <li><a href=\"%s%s\">%s%s</a></li>\n", path, sep, path, sep); match = 2; }
int get_login(struct cgit_context *ctx, char *remote_user, MemoryStruct *chunk) { CURLcode res; CURL *curl; curl = curl_easy_init(); struct curl_slist * headers=NULL; headers = curl_slist_append(headers, remote_user); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_URL, ctx->cfg.gerrit_login_url); //curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_COOKIE,getenv("HTTP_COOKIE") ); curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); //curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, WriteMemoryCallback2); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)chunk); res = curl_easy_perform(curl); #if MYDEBUG fprintf(stderr,"DEBUG: login response head ----> \n%s\n",chunk->memory); fprintf(stderr,"DEBUG: <-- login response head \n"); #endif int ret = 0; if(res != CURLE_OK) { fprintf(stderr, "error: get_login curl_easy_perform() failed: %s url: %s\n", curl_easy_strerror(res), ctx->cfg.gerrit_login_url); ret = -1; } else { char * line = NULL; line = strtok(chunk->memory, "\n"); int cookcnt = 0; char gerrit_cookie_name[] = "Set-Cookie: GerritAccount="; while(line != NULL) { #ifdef MYDEBUG fprintf(stderr,"DEBUG line by line ----> %s\n",line); #endif int ret2 = memcmp(line, gerrit_cookie_name ,sizeof(gerrit_cookie_name) -1 ); if(ret2 == 0) { #ifdef MYDEBUG fprintf(stderr,"DEBUG Gerrit Cookie found...\n"); #endif htmlf("%s\n", line); cookcnt++; } line = strtok(NULL,"\n"); } #ifdef MYDEBUG fprintf(stderr,"DEBUG: cookcnt:%d\n",cookcnt); #endif if(cookcnt == 0) { ret = -1; } } curl_easy_cleanup(curl); return ret; }
static void print_combined_authorrow(struct string_list *authors, int from, int to, const char *name, const char *leftclass, const char *centerclass, const char *rightclass, const struct cgit_period *period) { struct string_list_item *author; struct authorstat *authorstat; struct string_list *items; struct string_list_item *date; time_t now; long i, j, total, subtotal; struct tm *tm; char *tmp; time(&now); tm = gmtime(&now); period->trunc(tm); for (i = 1; i < period->count; i++) period->dec(tm); total = 0; htmlf("<tr><td class='%s'>%s</td>", leftclass, fmt(name, to - from + 1)); for (j = 0; j < period->count; j++) { tmp = period->pretty(tm); period->inc(tm); subtotal = 0; for (i = from; i <= to; i++) { author = &authors->items[i]; authorstat = author->util; items = &authorstat->list; date = string_list_lookup(items, tmp); if (date) subtotal += (size_t)date->util; } htmlf("<td class='%s'>%ld</td>", centerclass, subtotal); total += subtotal; } htmlf("<td class='%s'>%ld</td></tr>", rightclass, total); }
static void print_url(const char *url) { int columns = 3; if (ctx.repo->enable_log_filecount) columns++; if (ctx.repo->enable_log_linecount) columns++; if (urls++ == 0) { htmlf("<tr class='nohover'><td colspan='%d'> </td></tr>", columns); htmlf("<tr><th class='left' colspan='%d'>Clone</th></tr>\n", columns); } htmlf("<tr><td colspan='%d'><a rel='vcs-git' href='", columns); html_url_path(url); html("' title='"); html_attr(ctx.repo->name); html(" Git repository'>"); html_txt(url); html("</a></td></tr>\n"); }
void print_commit(struct commit *commit) { struct commitinfo *info; char *tmp; int cols = 2; info = cgit_parse_commit(commit); htmlf("<tr%s><td>", ctx.qry.showmsg ? " class='logheader'" : ""); tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1)); tmp = cgit_fileurl(ctx.repo->url, "commit", ctx.qry.vpath, tmp); html_link_open(tmp, NULL, NULL); cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); html_link_close(); htmlf("</td><td%s>", ctx.qry.showmsg ? " class='logsubject'" : ""); cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0); show_commit_decorations(commit); html("</td><td>"); html_txt(info->author); if (ctx.repo->enable_log_filecount) { files = 0; add_lines = 0; rem_lines = 0; cgit_diff_commit(commit, inspect_files); html("</td><td>"); htmlf("%d", files); if (ctx.repo->enable_log_linecount) { html("</td><td>"); htmlf("-%d/+%d", rem_lines, add_lines); } } html("</td></tr>\n"); if (ctx.qry.showmsg) { struct strbuf notes = STRBUF_INIT; format_note(NULL, commit->object.sha1, ¬es, PAGE_ENCODING, 0); if (ctx.repo->enable_log_filecount) { cols++; if (ctx.repo->enable_log_linecount) cols++; } htmlf("<tr class='nohover'><td/><td colspan='%d' class='logmsg'>", cols); html_txt(info->msg); html("</td></tr>\n"); if (notes.len != 0) { html("<tr class='nohover'>"); html("<td class='lognotes-label'>Notes:</td>"); htmlf("<td colspan='%d' class='lognotes'>", cols); html_txt(notes.buf); html("</td></tr>\n"); } strbuf_release(¬es); } cgit_free_commitinfo(info); }
void cgit_print_summary() { int columns = 3; if (ctx.repo->enable_log_filecount) columns++; if (ctx.repo->enable_log_linecount) columns++; html("<table summary='repository info' class='list nowrap'>"); cgit_print_branches(ctx.cfg.summary_branches); htmlf("<tr class='nohover'><td colspan='%d'> </td></tr>", columns); cgit_print_tags(ctx.cfg.summary_tags); if (ctx.cfg.summary_log > 0) { htmlf("<tr class='nohover'><td colspan='%d'> </td></tr>", columns); cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL, NULL, NULL, 0, 0, 0); } urls = 0; cgit_add_clone_urls(print_url); html("</table>"); }
static void print_pack_info(void) { struct packed_git *pack; int ofs; ctx.page.mimetype = "text/plain"; ctx.page.filename = "objects/info/packs"; cgit_print_http_headers(); ofs = strlen(ctx.repo->path) + strlen("/objects/pack/"); prepare_packed_git(); for (pack = packed_git; pack; pack = pack->next) if (pack->pack_local) htmlf("P %s\n", pack->pack_name + ofs); }
void cgit_print_patch(char *hex, const char *prefix) { struct commit *commit; struct commitinfo *info; unsigned char sha1[20], old_sha1[20]; char *patchname; if (!hex) hex = ctx.qry.head; if (get_sha1(hex, sha1)) { cgit_print_error(fmt("Bad object id: %s", hex)); return; } commit = lookup_commit_reference(sha1); if (!commit) { cgit_print_error(fmt("Bad commit reference: %s", hex)); return; } info = cgit_parse_commit(commit); if (commit->parents && commit->parents->item) hashcpy(old_sha1, commit->parents->item->object.sha1); else hashclr(old_sha1); patchname = fmt("%s.patch", sha1_to_hex(sha1)); ctx.page.mimetype = "text/plain"; ctx.page.filename = patchname; cgit_print_http_headers(&ctx); htmlf("From %s Mon Sep 17 00:00:00 2001\n", sha1_to_hex(sha1)); htmlf("From: %s", info->author); if (!ctx.cfg.noplainemail) { htmlf(" %s", info->author_email); } html("\n"); html("Date: "); cgit_print_date(info->author_date, "%a, %d %b %Y %H:%M:%S %z%n", ctx.cfg.local_time); htmlf("Subject: %s\n\n", info->subject); if (info->msg && *info->msg) { htmlf("%s", info->msg); if (info->msg[strlen(info->msg) - 1] != '\n') html("\n"); } html("---\n"); if (prefix) htmlf("(limited to '%s')\n\n", prefix); cgit_diff_tree(old_sha1, sha1, filepair_cb, prefix, 0); html("--\n"); htmlf("cgit %s\n", CGIT_VERSION); cgit_free_commitinfo(info); }
void cgit_print_diffstat(const unsigned char *old_sha1, const unsigned char *new_sha1, const char *prefix) { int i, save_context = ctx.qry.context; html("<div class='diffstat-header'>"); cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1, ctx.qry.sha2, NULL, 0); if (prefix) htmlf(" (limited to '%s')", prefix); html(" ("); ctx.qry.context = (save_context > 0 ? save_context : 3) << 1; cgit_self_link("more", NULL, NULL, &ctx); html("/"); ctx.qry.context = (save_context > 3 ? save_context : 3) >> 1; cgit_self_link("less", NULL, NULL, &ctx); ctx.qry.context = save_context; html(" context)"); html(" ("); ctx.qry.ignorews = (ctx.qry.ignorews + 1) % 2; cgit_self_link(ctx.qry.ignorews ? "ignore" : "show", NULL, NULL, &ctx); ctx.qry.ignorews = (ctx.qry.ignorews + 1) % 2; html(" whitespace changes)"); html("</div>"); html("<table summary='diffstat' class='diffstat'>"); max_changes = 0; cgit_diff_tree(old_sha1, new_sha1, inspect_filepair, prefix, ctx.qry.ignorews); for(i = 0; i<files; i++) print_fileinfo(&items[i]); html("</table>"); html("<div class='diffstat-summary'>"); htmlf("%d files changed, %d insertions, %d deletions", files, total_adds, total_rems); html("</div>"); }
static void print_dir(const unsigned char *sha1, const char *path, const char *base) { char *fullpath; if (path[0] || base[0]) fullpath = fmt("/%s%s/", base, path); else fullpath = "/"; ctx.page.etag = sha1_to_hex(sha1); cgit_print_http_headers(&ctx); htmlf("<html><head><title>%s</title></head>\n<body>\n" " <h2>%s</h2>\n <ul>\n", fullpath, fullpath); if (path[0] || base[0]) html(" <li><a href=\"../\">../</a></li>\n"); match = 2; }
void cgit_print_tag(char *revname) { unsigned char sha1[20]; struct object *obj; struct tag *tag; struct taginfo *info; if (get_sha1(revname, sha1)) { cgit_print_error(fmt("Bad tag reference: %s", revname)); return; } obj = parse_object(sha1); if (!obj) { cgit_print_error(fmt("Bad object id: %s", sha1_to_hex(sha1))); return; } if (obj->type == OBJ_TAG) { tag = lookup_tag(sha1); if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) { cgit_print_error(fmt("Bad tag object: %s", revname)); return; } html("<table class='commit-info'>\n"); htmlf("<tr><td>Tag name</td><td>%s (%s)</td></tr>\n", revname, 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("</td></tr>\n"); } if (info->tagger) { html("<tr><td>Tagged by</td><td>"); html_txt(info->tagger); if (info->tagger_email) { html(" "); html_txt(info->tagger_email); } html("</td></tr>\n"); } html("<tr><td>Tagged object</td><td>"); cgit_object_link(tag->tagged); html("</td></tr>\n"); html("</table>\n"); print_tag_content(info->msg); } return; }
int cache_ls(const char *path) { DIR *dir; struct dirent *ent; int err = 0; struct cache_slot slot = { NULL }; struct strbuf fullname = STRBUF_INIT; size_t prefixlen; if (!path) { cache_log("[cgit] cache path not specified\n"); return -1; } dir = opendir(path); if (!dir) { err = errno; cache_log("[cgit] unable to open path %s: %s (%d)\n", path, strerror(err), err); return err; } strbuf_addstr(&fullname, path); strbuf_ensure_end(&fullname, '/'); prefixlen = fullname.len; while ((ent = readdir(dir)) != NULL) { if (strlen(ent->d_name) != 8) continue; strbuf_setlen(&fullname, prefixlen); strbuf_addstr(&fullname, ent->d_name); slot.cache_name = fullname.buf; if ((err = open_slot(&slot)) != 0) { cache_log("[cgit] unable to open path %s: %s (%d)\n", fullname.buf, strerror(err), err); continue; } htmlf("%s %s %10"PRIuMAX" %s\n", fullname.buf, sprintftime("%Y-%m-%d %H:%M:%S", slot.cache_st.st_mtime), (uintmax_t)slot.cache_st.st_size, slot.buf); close_slot(&slot); } closedir(dir); strbuf_release(&fullname); return 0; }
static void print_pack_info(void) { struct packed_git *pack; char *offset; ctx.page.mimetype = "text/plain"; ctx.page.filename = "objects/info/packs"; cgit_print_http_headers(); prepare_packed_git(); for (pack = packed_git; pack; pack = pack->next) { if (pack->pack_local) { offset = strrchr(pack->pack_name, '/'); if (offset && offset[1] != '\0') ++offset; else offset = pack->pack_name; htmlf("P %s\n", offset); } } }
void cgit_print_repolist(void) { int i, columns = 3, hits = 0, header = 0; char *last_section = NULL; char *section; int sorted = 0; if (!any_repos_visible()) { cgit_print_error_page(404, "Not found", "No repositories found"); return; } if (ctx.cfg.enable_index_links) ++columns; if (ctx.cfg.enable_index_owner) ++columns; ctx.page.title = ctx.cfg.root_title; cgit_print_http_headers(); cgit_print_docstart(); cgit_print_pageheader(); if (ctx.cfg.index_header) html_include(ctx.cfg.index_header); if (ctx.qry.sort) sorted = sort_repolist(ctx.qry.sort); else if (ctx.cfg.section_sort) sort_repolist("section"); html("<table summary='repository list' class='list nowrap'>"); for (i = 0; i < cgit_repolist.count; i++) { ctx.repo = &cgit_repolist.repos[i]; if (!is_visible(ctx.repo)) continue; hits++; if (hits <= ctx.qry.ofs) continue; if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count) continue; if (!header++) print_header(); section = ctx.repo->section; if (section && !strcmp(section, "")) section = NULL; if (!sorted && ((last_section == NULL && section != NULL) || (last_section != NULL && section == NULL) || (last_section != NULL && section != NULL && strcmp(section, last_section)))) { htmlf("<tr class='nohover'><td colspan='%d' class='reposection'>", columns); html_txt(section); html("</td></tr>"); last_section = section; } htmlf("<tr><td class='%s'>", !sorted && section ? "sublevel-repo" : "toplevel-repo"); cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); html("</td><td>"); html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL); html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc); html_link_close(); html("</td><td>"); if (ctx.cfg.enable_index_owner) { 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("<a href='"); html_attr(cgit_currenturl()); html("?q="); html_url_arg(ctx.repo->owner); html("'>"); html_txt(ctx.repo->owner); html("</a>"); } html("</td><td>"); } print_modtime(ctx.repo); html("</td>"); if (ctx.cfg.enable_index_links) { html("<td>"); cgit_summary_link("summary", NULL, "button", NULL); cgit_log_link("log", NULL, "button", NULL, NULL, NULL, 0, NULL, NULL, ctx.qry.showmsg, 0); cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); html("</td>"); } html("</tr>\n"); } html("</table>"); if (hits > ctx.cfg.max_repo_count) print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search, ctx.qry.sort); cgit_print_docend(); }
static void print_fileinfo(struct fileinfo *info) { char *class; switch (info->status) { case DIFF_STATUS_ADDED: class = "add"; break; case DIFF_STATUS_COPIED: class = "cpy"; break; case DIFF_STATUS_DELETED: class = "del"; break; case DIFF_STATUS_MODIFIED: class = "upd"; break; case DIFF_STATUS_RENAMED: class = "mov"; break; case DIFF_STATUS_TYPE_CHANGED: class = "typ"; break; case DIFF_STATUS_UNKNOWN: class = "unk"; break; case DIFF_STATUS_UNMERGED: class = "stg"; break; default: die("bug: unhandled diff status %c", info->status); } html("<tr>"); htmlf("<td class='mode'>"); if (is_null_sha1(info->new_sha1)) { cgit_print_filemode(info->old_mode); } else { cgit_print_filemode(info->new_mode); } if (info->old_mode != info->new_mode && !is_null_sha1(info->old_sha1) && !is_null_sha1(info->new_sha1)) { html("<span class='modechange'>["); cgit_print_filemode(info->old_mode); html("]</span>"); } htmlf("</td><td class='%s'>", class); cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, ctx.qry.sha2, info->new_path, 0); if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) htmlf(" (%s from %s)", info->status == DIFF_STATUS_COPIED ? "copied" : "renamed", info->old_path); html("</td><td class='right'>"); if (info->binary) { htmlf("bin</td><td class='graph'>%ld -> %ld bytes", info->old_size, info->new_size); return; } htmlf("%d", info->added + info->removed); html("</td><td class='graph'>"); htmlf("<table summary='file diffstat' width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes)); htmlf("<td class='add' style='width: %.1f%%;'/>", info->added * 100.0 / max_changes); htmlf("<td class='rem' style='width: %.1f%%;'/>", info->removed * 100.0 / max_changes); htmlf("<td class='none' style='width: %.1f%%;'/>", (max_changes - info->removed - info->added) * 100.0 / max_changes); html("</tr></table></td></tr>\n"); }
void html_status(int code, const char *msg, int more_headers) { htmlf("Status: %d %s\n", code, msg); if (!more_headers) html("\n"); }
void print_commit(struct commit *commit, struct rev_info *revs) { struct commitinfo *info; int cols = revs->graph ? 3 : 2; struct strbuf graphbuf = STRBUF_INIT; struct strbuf msgbuf = STRBUF_INIT; if (ctx.repo->enable_log_filecount) cols++; if (ctx.repo->enable_log_linecount) cols++; if (revs->graph) { /* Advance graph until current commit */ while (!graph_next_line(revs->graph, &graphbuf)) { /* Print graph segment in otherwise empty table row */ html("<tr class='nohover'><td class='commitgraph'>"); html(graphbuf.buf); htmlf("</td><td colspan='%d' /></tr>\n", cols); strbuf_setlen(&graphbuf, 0); } /* Current commit's graph segment is now ready in graphbuf */ } info = cgit_parse_commit(commit); htmlf("<tr%s>", ctx.qry.showmsg ? " class='logheader'" : ""); if (revs->graph) { /* Print graph segment for current commit */ html("<td class='commitgraph'>"); html(graphbuf.buf); html("</td>"); strbuf_setlen(&graphbuf, 0); } else { html("<td>"); cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); html("</td>"); } htmlf("<td%s>", ctx.qry.showmsg ? " class='logsubject'" : ""); if (ctx.qry.showmsg) { /* line-wrap long commit subjects instead of truncating them */ size_t subject_len = strlen(info->subject); if (subject_len > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { /* symbol for signaling line-wrap (in PAGE_ENCODING) */ const char wrap_symbol[] = { ' ', 0xE2, 0x86, 0xB5, 0 }; int i = ctx.cfg.max_msg_len - strlen(wrap_symbol); /* Rewind i to preceding space character */ while (i > 0 && !isspace(info->subject[i])) --i; if (!i) /* Oops, zero spaces. Reset i */ i = ctx.cfg.max_msg_len - strlen(wrap_symbol); /* add remainder starting at i to msgbuf */ strbuf_add(&msgbuf, info->subject + i, subject_len - i); strbuf_trim(&msgbuf); strbuf_add(&msgbuf, "\n\n", 2); /* Place wrap_symbol at position i in info->subject */ strcpy(info->subject + i, wrap_symbol); } } cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0); show_commit_decorations(commit); html("</td><td>"); html_txt(info->author); if (revs->graph) { html("</td><td>"); cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); } if (ctx.repo->enable_log_filecount || ctx.repo->enable_log_linecount) { files = 0; add_lines = 0; rem_lines = 0; cgit_diff_commit(commit, inspect_files, ctx.qry.vpath); } 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); html("</td></tr>\n"); if (revs->graph || ctx.qry.showmsg) { /* Print a second table row */ html("<tr class='nohover'>"); if (ctx.qry.showmsg) { /* Concatenate commit message + notes in msgbuf */ if (info->msg && *(info->msg)) { strbuf_addstr(&msgbuf, info->msg); strbuf_addch(&msgbuf, '\n'); } format_note(NULL, commit->object.sha1, &msgbuf, PAGE_ENCODING, NOTES_SHOW_HEADER | NOTES_INDENT); strbuf_addch(&msgbuf, '\n'); strbuf_ltrim(&msgbuf); } if (revs->graph) { int lines = 0; /* Calculate graph padding */ if (ctx.qry.showmsg) { /* Count #lines in commit message + notes */ const char *p = msgbuf.buf; lines = 1; while ((p = strchr(p, '\n'))) { p++; lines++; } } /* Print graph padding */ html("<td class='commitgraph'>"); while (lines > 0 || !graph_is_commit_finished(revs->graph)) { if (graphbuf.len) html("\n"); strbuf_setlen(&graphbuf, 0); graph_next_line(revs->graph, &graphbuf); html(graphbuf.buf); lines--; } html("</td>\n"); } else html("<td/>"); /* Empty 'Age' column */ /* Print msgbuf into remainder of table row */ htmlf("<td colspan='%d'%s>\n", cols, ctx.qry.showmsg ? " class='logmsg'" : ""); html_txt(msgbuf.buf); html("</td></tr>\n"); } strbuf_release(&msgbuf); strbuf_release(&graphbuf); cgit_free_commitinfo(info); }