/* ui-wiki.c: functions for wiki output * * Copyright (C) 2006-2017 cgit Development Team * Copyright (C) 2025 Freya Murphy * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */ #define USE_THE_REPOSITORY_VARIABLE #include "cgit.h" #include "ui-wiki.h" #include "html.h" #include "ui-shared.h" #define WIKI_PATH ".wiki" struct walk_wiki_context { char *curr_rev; int state; int index; }; static void print_page(const struct object_id *oid, const char *path, const char *basename, const char *rev) { enum object_type type; unsigned long size; char *buf; type = odb_read_object_info(the_repository->objects, oid, &size); if (type == OBJ_BAD) { cgit_print_error_page(404, "Not found", "Bad object name: %s", oid_to_hex(oid)); return; } buf = odb_read_object(the_repository->objects, oid, &type, &size); if (!buf) { cgit_print_error_page(500, "Internal server error", "Error reading object %s", oid_to_hex(oid)); return; } html("
"); cgit_open_filter(ctx.repo->about_filter, basename); html_raw(buf, size); cgit_close_filter(ctx.repo->about_filter); html("
"); free(buf); } static int ls_wiki(const struct object_id *oid, const char *pathname, struct walk_wiki_context *walk_wiki_ctx) { char *name, *link, *ptr; if (isdigit(*pathname)) { long index = strtol(pathname, &ptr, 10); if (ptr && *ptr == '-') { pathname = ptr + 1; walk_wiki_ctx->index = index; } } name = xstrdup(pathname); ptr = strrchr(name, '.'); if (ptr) *ptr = '\0'; link = xstrdup(name); for (ptr = name; *ptr; ptr++) { if (*ptr == '-') *ptr = ' '; } for (ptr = link; *ptr; ptr++) *ptr = tolower(*ptr); html(""); htmlf("%d", walk_wiki_ctx->index); html(""); cgit_wiki_link(name, NULL, "ls-link", ctx.qry.head, walk_wiki_ctx->curr_rev, link); html("\n"); walk_wiki_ctx->index++; free(name); free(link); return 0; } static void ls_head(void) { cgit_print_layout_start(); html("\n"); html(""); html(""); html(""); html("\n"); } static void ls_tail(void) { html("
IndexTitle"); html("
\n"); } static int walk_wiki(const struct object_id *oid, struct strbuf *base, const char *pathname, unsigned mode, void *cbdata) { struct walk_wiki_context *walk_wiki_ctx = cbdata; if (!strcmp(pathname, WIKI_PATH)) return READ_TREE_RECURSIVE; if (walk_wiki_ctx->state < 2) { if (walk_wiki_ctx->state == 0) { walk_wiki_ctx->state = 1; ls_head(); } ls_wiki(oid, pathname, walk_wiki_ctx); } else if (walk_wiki_ctx->state == 2) { const char *name; name = pathname; if (isdigit(*name)) { char *ptr; strtol(name, &ptr, 10); if (ptr && *ptr == '-') name = ptr + 1; } if (!strncasecmp(name, ctx.qry.path, strlen(ctx.qry.path))) { struct strbuf buffer = STRBUF_INIT; strbuf_addbuf(&buffer, base); strbuf_addstr(&buffer, pathname); walk_wiki_ctx->state = 3; print_page(oid, pathname, buffer.buf, walk_wiki_ctx->curr_rev); strbuf_release(&buffer); } } return 0; } /* * Show repo wiki * rev: the commit pointing at the root ui object * path: partial name of a wiki md file */ void cgit_print_wiki(const char *rev) { struct object_id oid; struct commit *commit; struct pathspec_item path_items = { .match = WIKI_PATH, .len = sizeof(WIKI_PATH) - 1, }; struct pathspec paths = { .nr = 1, .items = &path_items }; struct walk_wiki_context walk_wiki_ctx = { .state = 0, .index = 1 }; if (!rev) rev = ctx.qry.head; if (repo_get_oid(the_repository, rev, &oid)) { cgit_print_error_page(404, "Not found", "Invalid revision name: %s", rev); return; } commit = lookup_commit_reference(the_repository, &oid); if (!commit || repo_parse_commit(the_repository, commit)) { cgit_print_error_page(404, "Not found", "Invalid commit reference: %s", rev); return; } walk_wiki_ctx.curr_rev = xstrdup(rev); // print wiki pages read_tree(the_repository, repo_get_commit_tree(the_repository, commit), &paths, walk_wiki, &walk_wiki_ctx); if (walk_wiki_ctx.state == 0) { cgit_print_error_page(404, "Not found", "Wiki not found"); goto cleanup; } ls_tail(); // print active wiki page if (ctx.qry.path) { html("
\n"); walk_wiki_ctx.state = 2; read_tree(the_repository, repo_get_commit_tree(the_repository, commit), &paths, walk_wiki, &walk_wiki_ctx); if (walk_wiki_ctx.state == 2) cgit_print_error("Wiki page not found"); } cgit_print_layout_end(); cleanup: free(walk_wiki_ctx.curr_rev); }